Skip to content

feat: add dependency proxy toolset#474

Open
babyhuey wants to merge 11 commits into
zereight:mainfrom
babyhuey:main
Open

feat: add dependency proxy toolset#474
babyhuey wants to merge 11 commits into
zereight:mainfrom
babyhuey:main

Conversation

@babyhuey
Copy link
Copy Markdown

@babyhuey babyhuey commented May 13, 2026

Closes #473

Summary

  • Adds 4 new MCP tools for GitLab's group-level Dependency Proxy API
  • New opt-in toolset dependency_proxy (isDefault: false) — activate via GITLAB_TOOLSETS=dependency_proxy or discover_tools
  • Three tools use the GitLab GraphQL API (the only REST endpoint is the cache purge)
  • All tools are group-scoped, consistent with existing group-level tools

Tools added

Tool API Endpoint Read-only Destructive
get_dependency_proxy_settings GraphQL group { dependencyProxySetting ... }
update_dependency_proxy_settings GraphQL mutation updateDependencyProxySettings
list_dependency_proxy_blobs GraphQL group { dependencyProxyBlobs ... }
purge_dependency_proxy_cache REST DELETE /groups/:id/dependency_proxy/cache

Files changed

  • schemas.ts — 2 response types + 4 input schemas
  • index.ts — 4 API functions + 4 switch case handlers
  • tools/registry.ts — tool entries, readOnlyTools, destructiveTools, ToolsetId union, toolset definition
  • test/test-dependency-proxy.ts — integration tests
  • test/schema-tests.ts — Zod parse tests for new response types
  • test/test-toolset-filtering.ts — updated toolset counts

Test plan

  • get_dependency_proxy_settings returns settings for a group
  • update_dependency_proxy_settings enables proxy and returns updated settings
  • update_dependency_proxy_settings rejects calls with no update fields
  • list_dependency_proxy_blobs returns paginated blob list with string sizes
  • purge_dependency_proxy_cache returns scheduled status message
  • Tools are absent when dependency_proxy toolset is not activated
  • Read-only mode blocks write/delete operations

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b8bcaf9ea

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread index.ts Outdated
Comment thread index.ts Outdated
Comment thread index.ts Outdated
Comment thread index.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d211c8b42d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread index.ts Outdated
Comment thread index.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2a442089c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread index.ts Outdated
dependencyProxyImageTtlPolicy { enabled ttl }
}
}`,
{ fullPath: groupPath }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve REST group IDs before GraphQL lookups

When group_id is a numeric ID or an encoded subgroup path such as my-org%2Fteam, the input schema accepts it, but this sends it unchanged as GraphQL fullPath. GitLab's group(fullPath:) and UpdateDependencyProxySettingsInput.groupPath require the real full path, so the get/list/update dependency proxy tools fail for valid REST-style group identifiers that other group tools support; decode paths or resolve /groups/:id to full_path before issuing GraphQL.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner

@zereight zereight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update, and 0a2cdc4—the overall direction looks good. The dependency proxy being an opt-in non-default toolset makes sense.

I’m requesting changes for two actionable issues here; there are existing inline comments about the group ID / GraphQL path mismatch that should also be addressed in the same pass.

1. Merge conflict with main
The PR is currently CONFLICTING / DIRTY and cannot merge until it is rebased or conflicts are resolved.

2. New test file is not wired into CI
test/test-dependency-proxy.ts is added but does not appear in the test:mock script in package.json. This repository enumerates test files explicitly, so the new tests will not run under npm test / npm run test:all. Please add it to the test:mock script so the regression coverage is exercised in CI.

@babyhuey
Copy link
Copy Markdown
Author

Thanks for the detailed review — all three issues are addressed in this update.

Merge conflict resolved — rebased onto current main (picked up the update_issue_description_patch and branch tools). The README tool list is updated with correct numbering (156–159 for the dependency proxy tools).

Test wired into CItest/test-dependency-proxy.ts is now appended to the test:mock script in package.json, so npm run test:all exercises it.

Group ID / GraphQL path mismatch — added a resolveGroupFullPath() helper that:

  • Decodes URL-encoded paths (e.g. my-org%2Fteammy-org/team) before passing to GraphQL
  • Resolves numeric IDs by calling GET /groups/:id and using the returned full_path

All three GraphQL-based tools (get_dependency_proxy_settings, update_dependency_proxy_settings, list_dependency_proxy_blobs) call this before issuing their queries. The REST-based purge tool uses the existing decodeURIComponent/encodeURIComponent pattern consistent with peer group handlers.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c195828ad

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tools/registry.ts
"list_webhooks",
"list_webhook_events",
"get_webhook_event",
"get_dependency_proxy_settings",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep settings lookup out of read-only mode

When GITLAB_READ_ONLY_MODE=true, this still exposes get_dependency_proxy_settings, but that tool queries dependencyProxySetting; GitLab's current GroupType resolver backs that field with group.dependency_proxy_setting || group.create_dependency_proxy_setting, so a “read” against a group that has no settings row yet writes one to the GitLab database. This breaks the server's read-only contract for those groups; either avoid this field in read-only mode or don't classify the tool as read-only.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner

@zereight zereight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow-up commit 8c19582 — the GraphQL rewrite, resolveGroupFullPath, and wiring test/test-dependency-proxy.ts into test:mock address my earlier review items.

I'm still requesting changes for one blocking issue:

Build fails on current head
npm run build fails with TS18046: 'data' is of type 'unknown' at resolveGroupFullPath (index.ts:7825). Please parse the /groups/:id response with an existing Zod schema (same pattern as other REST helpers) instead of reading data.full_path from an unknown value.

Residual (non-blocking): consider documenting or avoiding the dependencyProxySetting GraphQL field in read-only deployments — GitLab's Group#dependency_proxy_setting uses a lazy build_dependency_proxy_setting fallback.

Comment thread index.ts Outdated
const response = await fetch(`${getEffectiveApiUrl()}/groups/${decoded}`, getFetchConfig());
await handleGitLabError(response);
const data = await response.json();
return data.full_path as string;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails npm run build on current main because response.json() is typed as unknown under the repo TypeScript settings. Could we parse the /groups/:id response with an existing Zod group schema (same pattern as other REST helpers) instead of data.full_path as string?

@babyhuey
Copy link
Copy Markdown
Author

Sorry about that — fixed in the latest commit. Replaced the unsafe data.full_path as string cast with z.object({ full_path: z.string() }).parse(await response.json()) to match the Zod parse pattern used elsewhere in the codebase.

@zereight
Copy link
Copy Markdown
Owner

zereight commented May 24, 2026

Thanks for addressing the earlier feedback — the resolveGroupFullPath typing fix and wiring test/test-dependency-proxy.ts into test:mock look good on the latest head.

The PR is still merge-conflicting with main. Could you please rebase onto the latest main and resolve the conflicts (e.g. README.md, index.ts, package.json, schemas.ts, and any registry/test paths that changed on both sides), then push the updated branch?

@babyhuey
Copy link
Copy Markdown
Author

Rebased onto current main (v2.1.15, picks up the markdown upload, approved_by_usernames, label schema, and deps bump).

One small note for the future: this PR has now been rebased three times in response to review requests, each time because new commits landed on main between when you asked for the rebase and when it was done. If it's easier, merging this one before landing the next batch of features would save another round. Happy to do whatever works best for your workflow.

@babyhuey
Copy link
Copy Markdown
Author

Verified locally against the same steps CI runs:

  • npm run build — clean (no errors)
  • npm run test:remote-auth — passed
  • npm run test:mock — all tests passed (including the dependency proxy suite)
  • npx tsc --noEmit — clean

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4836aa4c32

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread index.ts
Comment on lines +7996 to +7998
if (/^\d+$/.test(decoded)) {
const response = await fetch(`${getEffectiveApiUrl()}/groups/${decoded}`, getFetchConfig());
await handleGitLabError(response);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve numeric group paths when resolving full path

resolveGroupFullPath treats any all-digit group_id as a numeric ID and immediately calls GET /groups/:id. That breaks valid numeric-only group paths (for example "5000"): instead of querying that path in GraphQL, these tools resolve or fail against group ID 5000. Because the input schema explicitly accepts "ID or URL-encoded path", this can make get_dependency_proxy_settings, update_dependency_proxy_settings, and list_dependency_proxy_blobs target the wrong group or return 404 for legitimate path inputs.

Useful? React with 👍 / 👎.

@babyhuey
Copy link
Copy Markdown
Author

Rebased again. Fourth time now.

The conflict is the same every single time: a new test file lands on main while this PR waits for review. At this point keeping up with the rebase requests is its own full time job. Would be great to actually get a review before the next commit drops.

@babyhuey babyhuey force-pushed the main branch 2 times, most recently from 752c819 to ab4fc2e Compare May 26, 2026 00:11
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Hannah Lyons added 6 commits May 26, 2026 12:10
Adds five tools for interacting with the GitLab group-level dependency
proxy API: get/update settings, list blobs, delete a blob, and purge the
cache. Exposed as an opt-in toolset (dependency_proxy, isDefault: false).
- GET/PATCH /groups/:id/dependency_proxy and GET/DELETE blobs do not
  exist as REST endpoints; only DELETE /cache is documented. Rewrote
  get_dependency_proxy_settings, update_dependency_proxy_settings, and
  list_dependency_proxy_blobs to use the GraphQL API instead.
- Removed delete_dependency_proxy_blob (no REST or GraphQL equivalent).
- Fixed GitLabDependencyProxyBlobSchema.size to z.string() (GitLab
  returns a human-readable string, not a number).
- Fixed purge success message to "scheduled" (GitLab returns 202 and
  queues a background job, not an immediate delete).
- Added dependency_proxy to test-toolset-filtering.ts counts/samples.
- Add test/test-dependency-proxy.ts covering get settings, list blobs,
  purge cache, toolset activation, and read-only mode enforcement
- Add GitLabDependencyProxySchema and GitLabDependencyProxyBlobSchema
  tests to test/schema-tests.ts (6 new cases, 90 total)
- Add 4 new tools to README.md tool list (155-158)
- Guard updateDependencyProxySettings against no-op calls with no
  update fields provided
- Raise an error when updateDependencyProxySettings mutation returns
  payload-level errors rather than silently succeeding
- Decode group_id before re-encoding in purgeDependencyProxyCache to
  avoid double-encoding pre-encoded paths
- Use z.coerce.string() for all 4 group_id fields (matches every peer
  schema in the codebase; allows numeric IDs to be auto-coerced)
- Standardize group_id description to "Group ID or URL-encoded path"
  across all 4 input schemas
- Simplify purgeDependencyProxyCache to plain encodeURIComponent(groupId)
  instead of the unusual decode-then-re-encode pattern
- Fix GraphQL mock router collision: check for updateDependencyProxySettings
  mutation before the dependencyProxySetting query substring match
- Add success-path test for update_dependency_proxy_settings
- Update design spec to reflect actual implementation (4 tools, GraphQL)
Hannah Lyons added 5 commits May 26, 2026 12:10
…ructor

- remove "TTL" from update_dependency_proxy_settings description (no ttl
  field in the input schema)
- pass { port, validTokens } config object to MockGitLabServer constructor
  (positional number was wrong type per MockGitLabConfig interface)
- reject(response.error) rejected with a plain object, causing
  assert.rejects(/regex/) to never match; wrap in new Error() instead
- GITLAB_READ_ONLY_MODE only filters tools/list, not tools/call; rewrite
  the read-only test to verify write tools are absent from tools/list
  and read-only tools are still present
…to CI

- Add resolveGroupFullPath() helper: decodes URL-encoded paths, resolves
  numeric IDs to full_path via GET /groups/:id before GraphQL usage
- Use resolved fullPath in get/update/list dependency proxy GraphQL calls
- Use decode-then-encode pattern in purgeDependencyProxyCache (matches peers)
- Add test/test-dependency-proxy.ts to test:mock script in package.json
Replaces unsafe `data.full_path as string` cast with a typed Zod parse,
fixing TS18046 compile error reported in review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add dependency proxy tools

2 participants