gitlab-api 27.3.17__tar.gz → 27.3.19__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 (90) hide show
  1. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/PKG-INFO +6 -6
  2. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/README.md +4 -4
  3. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_base.py +19 -1
  4. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/gitlab_gql.py +2 -0
  5. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/gitlab_input_models.py +7 -1
  6. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/kg_ingest.py +1 -1
  7. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/mcp_server.py +29 -3
  8. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/certification.json +2 -2
  9. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/gitlab.ttl +1 -1
  10. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api.egg-info/PKG-INFO +6 -6
  11. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api.egg-info/SOURCES.txt +2 -0
  12. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api.egg-info/requires.txt +1 -1
  13. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/pyproject.toml +2 -2
  14. gitlab_api-27.3.19/tests/test_bug_002_005.py +91 -0
  15. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_cq_paths.py +1 -1
  16. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_kg_ingest.py +2 -2
  17. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_ontology_parent_link.py +2 -2
  18. gitlab_api-27.3.19/tests/test_paged_models_have_paging_fields.py +21 -0
  19. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/LICENSE +0 -0
  20. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/__init__.py +0 -0
  21. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/__main__.py +0 -0
  22. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/__init__.py +0 -0
  23. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_environments.py +0 -0
  24. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_issues.py +0 -0
  25. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_merge_requests.py +0 -0
  26. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_other.py +0 -0
  27. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_pipelines.py +0 -0
  28. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_projects.py +0 -0
  29. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_repositories.py +0 -0
  30. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_system.py +0 -0
  31. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_users_groups.py +0 -0
  32. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api/api_client_vulnerabilities.py +0 -0
  33. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/api_client.py +0 -0
  34. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/auth.py +0 -0
  35. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/connector_prep.py +0 -0
  36. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/connector_sources.py +0 -0
  37. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/gitlab_response_models.py +0 -0
  38. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/instances.py +0 -0
  39. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/mcp_config.json +0 -0
  40. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/__init__.py +0 -0
  41. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/access_contracts.ttl +0 -0
  42. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/fixtures/records.json +0 -0
  43. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/mappings/source.yaml +0 -0
  44. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/migrations/manifest.json +0 -0
  45. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/ontology/shapes/connector.shacl.ttl +0 -0
  46. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/prompts/devops_specialist.json +0 -0
  47. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-api-development/SKILL.md +0 -0
  48. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-api-operations/SKILL.md +0 -0
  49. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-api-operations/agents/openai.yaml +0 -0
  50. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-api-operations/references/catalog.md +0 -0
  51. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-issues/SKILL.md +0 -0
  52. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-issues/WORKFLOW.md +0 -0
  53. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-merge-request-create/SKILL.md +0 -0
  54. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-merge-request-create/WORKFLOW.md +0 -0
  55. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-merge-request-review/SKILL.md +0 -0
  56. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-merge-request-review/WORKFLOW.md +0 -0
  57. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-pipelines/SKILL.md +0 -0
  58. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-pipelines/WORKFLOW.md +0 -0
  59. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-vulnerabilities/SKILL.md +0 -0
  60. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api/skills/gitlab-vulnerabilities/WORKFLOW.md +0 -0
  61. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api.egg-info/dependency_links.txt +0 -0
  62. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api.egg-info/entry_points.txt +0 -0
  63. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/gitlab_api.egg-info/top_level.txt +0 -0
  64. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/scripts/check_import_safety.py +0 -0
  65. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/scripts/security_contract.py +0 -0
  66. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/setup.cfg +0 -0
  67. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/__init__.py +0 -0
  68. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/conftest.py +0 -0
  69. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_access_contracts.py +0 -0
  70. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_api_wrapper.py +0 -0
  71. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_auth.py +0 -0
  72. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_catalog_edges.py +0 -0
  73. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_connector_prep.py +0 -0
  74. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_fleet_name.py +0 -0
  75. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_gitlab_a2a_validation.py +0 -0
  76. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_gitlab_api_brute_force_coverage.py +0 -0
  77. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_gitlab_api_development_skill.py +0 -0
  78. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_gitlab_gql.py +0 -0
  79. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_gitlab_mcp_validation.py +0 -0
  80. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_gitlab_models.py +0 -0
  81. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_identity_context_scoping.py +0 -0
  82. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_ingest_sources.py +0 -0
  83. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_init_dynamics.py +0 -0
  84. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_instances.py +0 -0
  85. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_mock_coverage.py +0 -0
  86. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_pages_workflow.py +0 -0
  87. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_startup.py +0 -0
  88. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_tool_modes.py +0 -0
  89. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/test_verify_agent.py +0 -0
  90. {gitlab_api-27.3.17 → gitlab_api-27.3.19}/tests/verify_a2a_queries.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitlab-api
3
- Version: 27.3.17
3
+ Version: 27.3.19
4
4
  Summary: GitLab API + MCP Server
5
5
  Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: scion-sdk[graphql,mcp]<0.7.0,>=0.6.4
15
+ Requires-Dist: scion-sdk[graphql,mcp]<0.8.0,>=0.7.0
16
16
  Requires-Dist: python-dotenv>=1.2.4
17
17
  Provides-Extra: mcp
18
18
  Provides-Extra: all
@@ -105,8 +105,8 @@ _Auto-generated from the live MCP server — do not edit by hand._
105
105
  | `gitlab_graphql` | `GRAPHQLTOOL` | Execute raw GraphQL queries and mutations natively on GitLab. |
106
106
  | `gitlab_graphql_ops` | `GRAPHQL_OPSTOOL` | Run a typed GitLab GraphQL operation by name. |
107
107
  | `gitlab_groups` | `GROUPSTOOL` | Manage gitlab groups operations. |
108
- | `gitlab_ingest_pipelines` | `MISCTOOL` | Natively ingest GitLab CI pipeline runs (+ jobs) into epistemic-graph. |
109
- | `gitlab_ingest_projects` | `MISCTOOL` | Natively ingest GitLab projects into epistemic-graph as typed :Project nodes. |
108
+ | `gitlab_ingest_pipelines` | `MISCTOOL` | Natively ingest GitLab CI pipeline runs (+ jobs) into medulla. |
109
+ | `gitlab_ingest_projects` | `MISCTOOL` | Natively ingest GitLab projects into medulla as typed :Project nodes. |
110
110
  | `gitlab_instances` | `MISCTOOL` | List the configured GitLab tenants (CONCEPT:AU-KG.backend.declared-columns-so-schema). |
111
111
  | `gitlab_issues` | `ISSUESTOOL` | Manage GitLab issues. |
112
112
  | `gitlab_jobs` | `JOBSTOOL` | Manage gitlab jobs operations. |
@@ -368,7 +368,7 @@ When query strings or parameters are supplied, an LLM-free **Knowledge Graph res
368
368
 
369
369
  > **Install the connector-focused `[mcp]` extra.** Examples use `gitlab-api[mcp]` to add
370
370
  > FastMCP / FastAPI through `scion-sdk`; the required Scion SDK core
371
- > still carries `epistemic-graph[full]`. The `[agent-runtime]` extra additionally
371
+ > still carries `medulla`. The `[agent-runtime]` extra additionally
372
372
  > enables model orchestration.
373
373
 
374
374
  #### stdio Transport (local IDEs — Cursor, Claude Desktop, VS Code)
@@ -716,7 +716,7 @@ One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):
716
716
 
717
717
  | Image tag | Build target | Contents | Entrypoint |
718
718
  |-----------|--------------|----------|------------|
719
- | `example/gitlab-api:mcp` | `--target mcp` | `gitlab-api[mcp]` — **connector-focused**, includes `epistemic-graph[full]`; no model-orchestration stack | `gitlab-mcp` |
719
+ | `example/gitlab-api:mcp` | `--target mcp` | `gitlab-api[mcp]` — **connector-focused**, includes `medulla`; no model-orchestration stack | `gitlab-mcp` |
720
720
 
721
721
  ```bash
722
722
  docker build --target mcp -t example/gitlab-api:mcp docker/ # connector-focused MCP server
@@ -80,8 +80,8 @@ _Auto-generated from the live MCP server — do not edit by hand._
80
80
  | `gitlab_graphql` | `GRAPHQLTOOL` | Execute raw GraphQL queries and mutations natively on GitLab. |
81
81
  | `gitlab_graphql_ops` | `GRAPHQL_OPSTOOL` | Run a typed GitLab GraphQL operation by name. |
82
82
  | `gitlab_groups` | `GROUPSTOOL` | Manage gitlab groups operations. |
83
- | `gitlab_ingest_pipelines` | `MISCTOOL` | Natively ingest GitLab CI pipeline runs (+ jobs) into epistemic-graph. |
84
- | `gitlab_ingest_projects` | `MISCTOOL` | Natively ingest GitLab projects into epistemic-graph as typed :Project nodes. |
83
+ | `gitlab_ingest_pipelines` | `MISCTOOL` | Natively ingest GitLab CI pipeline runs (+ jobs) into medulla. |
84
+ | `gitlab_ingest_projects` | `MISCTOOL` | Natively ingest GitLab projects into medulla as typed :Project nodes. |
85
85
  | `gitlab_instances` | `MISCTOOL` | List the configured GitLab tenants (CONCEPT:AU-KG.backend.declared-columns-so-schema). |
86
86
  | `gitlab_issues` | `ISSUESTOOL` | Manage GitLab issues. |
87
87
  | `gitlab_jobs` | `JOBSTOOL` | Manage gitlab jobs operations. |
@@ -343,7 +343,7 @@ When query strings or parameters are supplied, an LLM-free **Knowledge Graph res
343
343
 
344
344
  > **Install the connector-focused `[mcp]` extra.** Examples use `gitlab-api[mcp]` to add
345
345
  > FastMCP / FastAPI through `scion-sdk`; the required Scion SDK core
346
- > still carries `epistemic-graph[full]`. The `[agent-runtime]` extra additionally
346
+ > still carries `medulla`. The `[agent-runtime]` extra additionally
347
347
  > enables model orchestration.
348
348
 
349
349
  #### stdio Transport (local IDEs — Cursor, Claude Desktop, VS Code)
@@ -691,7 +691,7 @@ One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):
691
691
 
692
692
  | Image tag | Build target | Contents | Entrypoint |
693
693
  |-----------|--------------|----------|------------|
694
- | `example/gitlab-api:mcp` | `--target mcp` | `gitlab-api[mcp]` — **connector-focused**, includes `epistemic-graph[full]`; no model-orchestration stack | `gitlab-mcp` |
694
+ | `example/gitlab-api:mcp` | `--target mcp` | `gitlab-api[mcp]` — **connector-focused**, includes `medulla`; no model-orchestration stack | `gitlab-mcp` |
695
695
 
696
696
  ```bash
697
697
  docker build --target mcp -t example/gitlab-api:mcp docker/ # connector-focused MCP server
@@ -5,6 +5,7 @@ from base64 import b64encode
5
5
  from typing import Any, TypeVar
6
6
 
7
7
  import requests
8
+ from scion_sdk.config import setting
8
9
  from scion_sdk.tls.profile import ResolvedTLSProfile
9
10
  from scion_sdk.tls.resolve import resolve_tls_profile
10
11
 
@@ -19,6 +20,23 @@ from scion_sdk.exceptions import (
19
20
 
20
21
  T = TypeVar("T")
21
22
 
23
+ DEFAULT_REQUEST_TIMEOUT = 30.0
24
+
25
+
26
+ def request_timeout() -> float:
27
+ """Seconds every GitLab REST call may take (env ``GITLAB_REQUEST_TIMEOUT``)."""
28
+ value = setting("GITLAB_REQUEST_TIMEOUT", DEFAULT_REQUEST_TIMEOUT, cast=float)
29
+ return value if value > 0 else DEFAULT_REQUEST_TIMEOUT
30
+
31
+
32
+ class _TimeoutSession(requests.Session):
33
+ """A session whose calls carry a timeout unless the caller sets one."""
34
+
35
+ def request(self, *args: Any, **kwargs: Any): # type: ignore[override]
36
+ if kwargs.get("timeout") is None:
37
+ kwargs["timeout"] = request_timeout()
38
+ return super().request(*args, **kwargs)
39
+
22
40
 
23
41
  def _normalize_base_url(url: str) -> str:
24
42
  """Strip a trailing /api/v4 (with or without slash) and re-append it once."""
@@ -75,7 +93,7 @@ class GitLabApiBase:
75
93
  if url is None:
76
94
  raise MissingParameterError
77
95
 
78
- self._session = requests.Session()
96
+ self._session = _TimeoutSession()
79
97
  self.url = _normalize_base_url(url)
80
98
  self.headers, self.headers_parallel = _build_auth_headers(
81
99
  token, tokens, username, password
@@ -14,6 +14,7 @@ from scion_sdk.tls.profile import ResolvedTLSProfile
14
14
  from scion_sdk.tls.resolve import resolve_tls_profile
15
15
  from scion_sdk.transports.graphql import GraphQLAuth, GraphQLClient
16
16
 
17
+ from gitlab_api.api.api_client_base import request_timeout
17
18
  from gitlab_api.gitlab_input_models import (
18
19
  BranchModel,
19
20
  CommitModel,
@@ -124,6 +125,7 @@ class GraphQL:
124
125
  auth=GraphQLAuth.bearer(token),
125
126
  tls_profile=self.tls_profile,
126
127
  tls_service="gitlab",
128
+ timeout=request_timeout(),
127
129
  fetch_schema=True,
128
130
  )
129
131
 
@@ -1278,7 +1278,7 @@ class MergeRequestModel(BaseModel):
1278
1278
  with_labels_details: bool | None = None
1279
1279
  with_merge_status_recheck: bool | None = None
1280
1280
  wip: str | None = None
1281
- title: str | None
1281
+ title: str | None = None
1282
1282
  allow_collaboration: bool | None = None
1283
1283
  allow_maintainer_to_push: bool | None = None
1284
1284
  approvals_before_merge: int | None = None
@@ -1775,6 +1775,9 @@ class NamespaceModel(BaseModel):
1775
1775
  top_level_only: bool | None = Field(
1776
1776
  description="Only show top level namespaces", default=None
1777
1777
  )
1778
+ max_pages: int | None = Field(
1779
+ description="Maximum number of pages to fetch", default=None
1780
+ )
1778
1781
  api_parameters: dict | None = Field(description="API Parameters", default=None)
1779
1782
  data: dict | None = Field(description="Data Payload", default=None)
1780
1783
 
@@ -2855,6 +2858,9 @@ class RunnerModel(BaseModel):
2855
2858
  runner_type: str | None = None
2856
2859
  status: str | None = None
2857
2860
  all_runners: bool | None = False
2861
+ max_pages: int | None = Field(
2862
+ description="Maximum number of pages to fetch", default=None
2863
+ )
2858
2864
  api_parameters: dict | None = Field(description="API Parameters", default=None)
2859
2865
  data: dict | None = Field(description="Data Payload", default=None)
2860
2866
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  CONCEPT:AU-KG.ingest.enterprise-source-extractor. This is the record-source twin of
4
4
  media-downloader's blob ingestion: the package pushes its data into the ONE
5
- epistemic-graph knowledge graph as **typed OWL nodes** (`:Project`, `:GitLabGroup`,
5
+ medulla knowledge graph as **typed OWL nodes** (`:Project`, `:GitLabGroup`,
6
6
  `:MergeRequest`, `:Issue`, …) + links through ``scion_sdk.ingest`` -- the
7
7
  generated ``SourceIngest`` client, not a local ingestion helper. Nodes carry shared
8
8
  provenance (via ``IngestBinding``) and match the classes federated by
@@ -48,6 +48,32 @@ def _parse_params(params_json: str) -> dict[str, Any] | None:
48
48
  return {k: v for k, v in kwargs.items() if v is not None}
49
49
 
50
50
 
51
+ def _graphql_failure(action: str, method: Any, exc: Exception, client: Any) -> dict:
52
+ """Describe a failed GraphQL operation with its real, redacted message."""
53
+ import inspect
54
+
55
+ from scion_sdk.httpsupport.redaction import redact_text
56
+
57
+ secrets = [t for t in (getattr(client, "token", None),) if t]
58
+ message = redact_text(str(exc), secrets) or type(exc).__name__
59
+ out: dict[str, Any] = {
60
+ "error": f"GraphQL operation '{action}' failed: {type(exc).__name__}: {message}"
61
+ }
62
+ if isinstance(exc, TypeError):
63
+ try:
64
+ params = [
65
+ p.name
66
+ for p in inspect.signature(method).parameters.values()
67
+ if p.kind in (p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY)
68
+ ]
69
+ except (TypeError, ValueError):
70
+ params = []
71
+ if params:
72
+ out["expected_params"] = params
73
+ out["error"] += f" (expected params_json keys: {', '.join(params)})"
74
+ return out
75
+
76
+
51
77
  def _by_keys(
52
78
  keys: tuple[str, ...], present: str, absent: str
53
79
  ) -> Callable[[dict[str, Any]], str]:
@@ -483,7 +509,7 @@ def register_misc_tools(mcp: FastMCP):
483
509
  client=Depends(get_client),
484
510
  ctx: Context | None = None,
485
511
  ) -> Any:
486
- """Natively ingest GitLab projects into epistemic-graph as typed :Project nodes.
512
+ """Natively ingest GitLab projects into medulla as typed :Project nodes.
487
513
 
488
514
  Lists projects via the GitLab API and pushes them (with their :GitLabGroup +
489
515
  :partOfGroup links) into the knowledge graph via the fast engine client.
@@ -516,7 +542,7 @@ def register_misc_tools(mcp: FastMCP):
516
542
  client=Depends(get_client),
517
543
  ctx: Context | None = None,
518
544
  ) -> Any:
519
- """Natively ingest GitLab CI pipeline runs (+ jobs) into epistemic-graph.
545
+ """Natively ingest GitLab CI pipeline runs (+ jobs) into medulla.
520
546
 
521
547
  Lists recent pipelines for ``project_id`` via the GitLab API (optionally each
522
548
  pipeline's jobs) and pushes them as typed ``:PipelineRun``/``:CheckRun`` nodes
@@ -1318,4 +1344,4 @@ def register_graphql_ops_tools(mcp: FastMCP):
1318
1344
  return await run_blocking(method, **{sole_model.name: model})
1319
1345
  return await run_blocking(method, **kwargs)
1320
1346
  except Exception as e:
1321
- return {"error": f"GraphQL operation '{action}' failed: {type(e).__name__}"}
1347
+ return _graphql_failure(action, method, e, client)
@@ -2,7 +2,7 @@
2
2
  "api_version": "graphos.io/v1",
3
3
  "artifacts": {
4
4
  "gitlab_api/ontology/fixtures/records.json": "5f0417820053941933f15b3f459750753f4e8e34cf1e7853fd030c1143356b40",
5
- "gitlab_api/ontology/gitlab.ttl": "c2f0687ebd6d70444b21488a163a181287764e3151650805a571172bbf6a08c0",
5
+ "gitlab_api/ontology/gitlab.ttl": "958c1fb5041914c84fcb039b6e1a3087dc9b90f1589c92897a2623e2078ccaf0",
6
6
  "gitlab_api/ontology/mappings/source.yaml": "4d845dd7df9503ae3a5d133ff00a98191d11adf3af7f6868f45c22bcbf098bb5",
7
7
  "gitlab_api/ontology/migrations/manifest.json": "442c3c53df0b42c866eef7255b1889b8ada6f9f9c5125cad65d6b50dc6362a3e",
8
8
  "gitlab_api/ontology/shapes/connector.shacl.ttl": "20d2bfc3827fd6327a3b6f25828b41d9de3f855867c46264a7e0aa7f951c76fa"
@@ -29,5 +29,5 @@
29
29
  "signer": "UNSIGNED-PREVIEW",
30
30
  "signing_public_key": "",
31
31
  "status": "source-validated",
32
- "validated_at": "2026-10-31T04:14:54Z"
32
+ "validated_at": "2026-11-06T16:19:16Z"
33
33
  }
@@ -11,7 +11,7 @@
11
11
  # per-package IRI. Backs the gitlab-api MCP tool surface (gitlab_projects / gitlab_merge_requests
12
12
  # / gitlab_pipelines / gitlab_issues / …).
13
13
 
14
- # Shared concepts owned by the epistemic-graph ontology and referenced here, never redeclared:
14
+ # Shared concepts owned by the medulla ontology and referenced here, never redeclared:
15
15
  # Commit, Branch, Release, Runner, Milestone, PipelineRun. Only the GitLab-specific subclasses and properties are declared in this pack.
16
16
 
17
17
  :GitLabGroup a owl:Class ;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitlab-api
3
- Version: 27.3.17
3
+ Version: 27.3.19
4
4
  Summary: GitLab API + MCP Server
5
5
  Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: scion-sdk[graphql,mcp]<0.7.0,>=0.6.4
15
+ Requires-Dist: scion-sdk[graphql,mcp]<0.8.0,>=0.7.0
16
16
  Requires-Dist: python-dotenv>=1.2.4
17
17
  Provides-Extra: mcp
18
18
  Provides-Extra: all
@@ -105,8 +105,8 @@ _Auto-generated from the live MCP server — do not edit by hand._
105
105
  | `gitlab_graphql` | `GRAPHQLTOOL` | Execute raw GraphQL queries and mutations natively on GitLab. |
106
106
  | `gitlab_graphql_ops` | `GRAPHQL_OPSTOOL` | Run a typed GitLab GraphQL operation by name. |
107
107
  | `gitlab_groups` | `GROUPSTOOL` | Manage gitlab groups operations. |
108
- | `gitlab_ingest_pipelines` | `MISCTOOL` | Natively ingest GitLab CI pipeline runs (+ jobs) into epistemic-graph. |
109
- | `gitlab_ingest_projects` | `MISCTOOL` | Natively ingest GitLab projects into epistemic-graph as typed :Project nodes. |
108
+ | `gitlab_ingest_pipelines` | `MISCTOOL` | Natively ingest GitLab CI pipeline runs (+ jobs) into medulla. |
109
+ | `gitlab_ingest_projects` | `MISCTOOL` | Natively ingest GitLab projects into medulla as typed :Project nodes. |
110
110
  | `gitlab_instances` | `MISCTOOL` | List the configured GitLab tenants (CONCEPT:AU-KG.backend.declared-columns-so-schema). |
111
111
  | `gitlab_issues` | `ISSUESTOOL` | Manage GitLab issues. |
112
112
  | `gitlab_jobs` | `JOBSTOOL` | Manage gitlab jobs operations. |
@@ -368,7 +368,7 @@ When query strings or parameters are supplied, an LLM-free **Knowledge Graph res
368
368
 
369
369
  > **Install the connector-focused `[mcp]` extra.** Examples use `gitlab-api[mcp]` to add
370
370
  > FastMCP / FastAPI through `scion-sdk`; the required Scion SDK core
371
- > still carries `epistemic-graph[full]`. The `[agent-runtime]` extra additionally
371
+ > still carries `medulla`. The `[agent-runtime]` extra additionally
372
372
  > enables model orchestration.
373
373
 
374
374
  #### stdio Transport (local IDEs — Cursor, Claude Desktop, VS Code)
@@ -716,7 +716,7 @@ One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):
716
716
 
717
717
  | Image tag | Build target | Contents | Entrypoint |
718
718
  |-----------|--------------|----------|------------|
719
- | `example/gitlab-api:mcp` | `--target mcp` | `gitlab-api[mcp]` — **connector-focused**, includes `epistemic-graph[full]`; no model-orchestration stack | `gitlab-mcp` |
719
+ | `example/gitlab-api:mcp` | `--target mcp` | `gitlab-api[mcp]` — **connector-focused**, includes `medulla`; no model-orchestration stack | `gitlab-mcp` |
720
720
 
721
721
  ```bash
722
722
  docker build --target mcp -t example/gitlab-api:mcp docker/ # connector-focused MCP server
@@ -62,6 +62,7 @@ tests/conftest.py
62
62
  tests/test_access_contracts.py
63
63
  tests/test_api_wrapper.py
64
64
  tests/test_auth.py
65
+ tests/test_bug_002_005.py
65
66
  tests/test_catalog_edges.py
66
67
  tests/test_connector_prep.py
67
68
  tests/test_cq_paths.py
@@ -79,6 +80,7 @@ tests/test_instances.py
79
80
  tests/test_kg_ingest.py
80
81
  tests/test_mock_coverage.py
81
82
  tests/test_ontology_parent_link.py
83
+ tests/test_paged_models_have_paging_fields.py
82
84
  tests/test_pages_workflow.py
83
85
  tests/test_startup.py
84
86
  tests/test_tool_modes.py
@@ -1,4 +1,4 @@
1
- scion-sdk[graphql,mcp]<0.7.0,>=0.6.4
1
+ scion-sdk[graphql,mcp]<0.8.0,>=0.7.0
2
2
  python-dotenv>=1.2.4
3
3
 
4
4
  [all]
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gitlab-api"
7
- version = "27.3.17"
7
+ version = "27.3.19"
8
8
  description = "GitLab API + MCP Server"
9
9
  readme = "README.md"
10
10
  classifiers = [ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: MIT License", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
11
11
  requires-python = ">=3.12"
12
- dependencies = [ "scion-sdk[graphql,mcp]>=0.6.4,<0.7.0", "python-dotenv>=1.2.4",]
12
+ dependencies = [ "scion-sdk[graphql,mcp]>=0.7.0,<0.8.0", "python-dotenv>=1.2.4",]
13
13
  [[project.authors]]
14
14
  name = "Repository Maintainers"
15
15
  email = "maintainers@knuckles.team"
@@ -0,0 +1,91 @@
1
+ """Optional kwargs are optional, GraphQL failures explain themselves, calls time out."""
2
+
3
+ from unittest.mock import patch
4
+
5
+ import pytest
6
+ from pydantic import BaseModel
7
+ from scion_sdk.connector import build_server
8
+
9
+ import gitlab_api.gitlab_input_models as input_models
10
+ from gitlab_api.api import api_client_base
11
+ from gitlab_api.gitlab_gql import GraphQL
12
+ from gitlab_api.mcp_server import _graphql_failure
13
+
14
+
15
+ def _is_optional(schema: dict) -> bool:
16
+ return any(b.get("type") == "null" for b in schema.get("anyOf", []))
17
+
18
+
19
+ def test_no_input_model_requires_an_optional_field():
20
+ bad = [
21
+ f"{cls.__name__}.{name}"
22
+ for cls in vars(input_models).values()
23
+ if isinstance(cls, type)
24
+ and issubclass(cls, BaseModel)
25
+ and cls.__module__ == input_models.__name__
26
+ for name, field in cls.model_fields.items()
27
+ if field.is_required() and "None" in str(field.annotation)
28
+ ]
29
+ assert bad == []
30
+
31
+
32
+ @pytest.mark.asyncio
33
+ async def test_no_tool_schema_requires_an_optional_field():
34
+ with patch("sys.argv", ["gitlab-mcp"]):
35
+ _, mcp = build_server("gitlab_api", command_args=[])
36
+ tools = await mcp.list_tools()
37
+ bad = [
38
+ f"{t.name}.{r}"
39
+ for t in tools
40
+ for r in (t.parameters or {}).get("required", [])
41
+ if _is_optional(t.parameters["properties"].get(r, {}))
42
+ ]
43
+ assert bad == []
44
+ mr = next(t for t in tools if t.name == "gitlab_get_project_merge_request")
45
+ assert "title" not in mr.parameters.get("required", [])
46
+
47
+
48
+ def test_graphql_failure_names_message_and_expected_kwargs():
49
+ method = getattr(GraphQL.update_merge_request, "__wrapped__", None)
50
+ try:
51
+ method(None, iid=1, projectId="x")
52
+ except TypeError as exc:
53
+ out = _graphql_failure(
54
+ "update_merge_request",
55
+ method,
56
+ exc,
57
+ type("C", (), {"token": "s3cr3t-token"})(),
58
+ )
59
+ assert "unexpected keyword argument" in out["error"]
60
+ assert "project_id" in out["expected_params"]
61
+ assert "merge_request_iid" in out["expected_params"]
62
+
63
+
64
+ def test_graphql_failure_redacts_the_token():
65
+ out = _graphql_failure(
66
+ "x",
67
+ lambda: None,
68
+ RuntimeError("boom Bearer abcdef0123456789 s3cr3t-token"),
69
+ type("C", (), {"token": "s3cr3t-token"})(),
70
+ )
71
+ assert "s3cr3t-token" not in out["error"]
72
+ assert "boom" in out["error"]
73
+
74
+
75
+ def test_rest_session_applies_a_default_timeout(monkeypatch):
76
+ monkeypatch.setenv("GITLAB_REQUEST_TIMEOUT", "7")
77
+ seen = {}
78
+
79
+ def fake(self, *a, **kw):
80
+ seen.update(kw)
81
+
82
+ with patch("requests.Session.request", fake):
83
+ api_client_base._TimeoutSession().request("GET", "http://x")
84
+ assert seen["timeout"] == 7.0
85
+ api_client_base._TimeoutSession().request("GET", "http://x", timeout=3)
86
+ assert seen["timeout"] == 3
87
+
88
+
89
+ def test_timeout_falls_back_on_bad_value(monkeypatch):
90
+ monkeypatch.setenv("GITLAB_REQUEST_TIMEOUT", "-1")
91
+ assert api_client_base.request_timeout() == api_client_base.DEFAULT_REQUEST_TIMEOUT
@@ -14,7 +14,7 @@ pytestmark = pytest.mark.spec("CONN-GITLAB-API-CONNECTOR-CONTENT-R004")
14
14
 
15
15
  PACKAGE = Path(gitlab_api.__file__).parent
16
16
  TTL = (PACKAGE / "ontology" / "gitlab.ttl").read_text("utf-8")
17
- # Concepts the epistemic-graph ontology owns: referenced, never declared here.
17
+ # Concepts the medulla ontology owns: referenced, never declared here.
18
18
  SHARED = ("Commit", "Branch", "Release", "Runner", "Milestone", "PipelineRun")
19
19
 
20
20
 
@@ -15,13 +15,13 @@ from typing import Any
15
15
 
16
16
  import pytest
17
17
  from scion_sdk.ingest import IngestError, KnowledgeIngest
18
- from epistemic_graph.generated.source_ingestion import SourceIngestionRequest
18
+ from medulla.generated.source_ingestion import SourceIngestionRequest
19
19
 
20
20
  from gitlab_api.kg_ingest import STREAM, ingest_pipeline_runs, ingest_projects
21
21
 
22
22
 
23
23
  class _FakeTransport:
24
- """Records every submitted request; no epistemic-graph engine required."""
24
+ """Records every submitted request; no medulla engine required."""
25
25
 
26
26
  def __init__(self) -> None:
27
27
  self.requests: list[SourceIngestionRequest] = []
@@ -1,4 +1,4 @@
1
- """Every class of the packaged ontology reaches an epistemic-graph parent class (CONN-GITLAB-API-CONNECTOR-CONTENT-R002)."""
1
+ """Every class of the packaged ontology reaches an medulla parent class (CONN-GITLAB-API-CONNECTOR-CONTENT-R002)."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -16,7 +16,7 @@ ONTOLOGIES = sorted(
16
16
  OWL = "http://www.w3.org/2002/07/owl#"
17
17
  RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
18
18
  SUBCLASS = "http://www.w3.org/2000/01/rdf-schema#subClassOf"
19
- # Parent classes of the epistemic-graph ontology that this connector links to or redeclares.
19
+ # Parent classes of the medulla ontology that this connector links to or redeclares.
20
20
  PARENT_CLASSES = frozenset(
21
21
  (
22
22
  "http://knuckles.team/kg#Commit",
@@ -0,0 +1,21 @@
1
+ """Every input model fed to the paged fetch carries the paging fields it reads."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from gitlab_api import gitlab_input_models as models
7
+
8
+ API_DIR = Path(__file__).parent.parent / "gitlab_api" / "api"
9
+ PAGED = re.compile(
10
+ r"(\w+) = (\w+Model)\(\*\*kwargs\)\s*\n\s*try:\s*\n\s*response, data = "
11
+ r"self\._fetch_all_pages\(\s*endpoint=[^\n]*\n\s*model=\1"
12
+ )
13
+
14
+
15
+ def test_paged_models_have_max_pages():
16
+ missing = set()
17
+ for path in API_DIR.glob("*.py"):
18
+ for _var, name in PAGED.findall(path.read_text()):
19
+ if "max_pages" not in getattr(models, name).model_fields:
20
+ missing.add(name)
21
+ assert not missing, sorted(missing)
File without changes
File without changes