Skip to content

feat(ai-proxy): add forest connectors#1505

Merged
nbouliol merged 29 commits intomainfrom
feat/ai-tools-integrations
Mar 31, 2026
Merged

feat(ai-proxy): add forest connectors#1505
nbouliol merged 29 commits intomainfrom
feat/ai-tools-integrations

Conversation

@nbouliol
Copy link
Copy Markdown
Member

@nbouliol nbouliol commented Mar 24, 2026

Definition of Done

General

  • Write an explicit title for the Pull Request, following Conventional Commits specification
  • Test manually the implemented changes
  • Validate the code quality (indentation, syntax, style, simplicity, readability)

Security

  • Consider the security impact of the changes made

Note

Add Zendesk connector and refactor tool providers into a unified ToolProvider abstraction

  • Introduces a ToolProvider interface with loadTools, checkConnection, and dispose methods, replacing direct McpClient lifecycle management in the router.
  • Adds ForestIntegrationClient supporting Zendesk as a Forest connector, exposing 6 Zendesk tools (get/create/update tickets, get/create comments) via ServerRemoteTool.
  • Adds BraveToolProvider to wrap Brave search tools; Brave is no longer auto-injected into RemoteTools but supplied via the provider pipeline.
  • Introduces createToolProviders factory that splits a heterogeneous Record<string, ToolConfig> into McpClient and ForestIntegrationClient instances.
  • Renames the routing parameter from mcpConfigs/mcpServerConfigs to toolConfigs across the router, agent, and public API surface; validMcpConfigurationOrThrow is renamed to validToolConfigurationOrThrow.
  • Behavioral Change: McpClient.loadTools now returns tools directly instead of accumulating internal state; testConnections/closeConnections are renamed to checkConnection/dispose.

Macroscope summarized 402767a.

@qltysh
Copy link
Copy Markdown

qltysh bot commented Mar 24, 2026

5 new issues

Tool Category Rule Count
qlty Duplication Found 27 lines of similar code in 2 locations (mass = 106) 2
qlty Structure Function with high complexity (count = 18): createUpdateTicketTool 2
qlty Structure Function with many returns (count = 4): route 1

@qltysh
Copy link
Copy Markdown

qltysh bot commented Mar 24, 2026

Qlty

Coverage Impact

⬆️ Merging this pull request will increase total coverage on main by 0.03%.

Modified Files with Diff Coverage (20)

RatingFile% DiffUncovered Line #s
Coverage rating: F Coverage rating: F
packages/agent-testing/src/forest-admin-client-mock.ts0.0%52
Coverage rating: A Coverage rating: A
packages/ai-proxy/src/remote-tools.ts100.0%
Coverage rating: A Coverage rating: A
packages/ai-proxy/src/router.ts100.0%
Coverage rating: A Coverage rating: A
packages/ai-proxy/src/oauth-token-injector.ts100.0%
Coverage rating: A Coverage rating: A
packages/ai-proxy/src/mcp-client.ts100.0%
Coverage rating: A Coverage rating: A
packages/ai-proxy/src/index.ts100.0%
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/permissions/forest-http-api.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/integrations/zendesk/tools/get-tickets.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/integrations/zendesk/tools/create-ticket.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/tool-provider-factory.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/integrations/zendesk/tools.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/forest-integration-client.ts100.0%
New file Coverage rating: C
packages/ai-proxy/src/integrations/brave/tools.ts75.0%12
New file Coverage rating: A
packages/ai-proxy/src/integrations/zendesk/tools/update-ticket.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/tool-source-checker.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/integrations/zendesk/utils.ts100.0%
New file Coverage rating: A
...-proxy/src/integrations/zendesk/tools/create-ticket-comment.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/integrations/zendesk/tools/get-ticket.ts100.0%
New file Coverage rating: A
...ai-proxy/src/integrations/zendesk/tools/get-ticket-comments.ts100.0%
New file Coverage rating: A
packages/ai-proxy/src/integrations/brave/brave-tool-provider.ts100.0%
Total98.9%
🤖 Increase coverage with AI coding...

In the `feat/ai-tools-integrations` branch, add test coverage for this new code:

- `packages/agent-testing/src/forest-admin-client-mock.ts` -- Line 52
- `packages/ai-proxy/src/integrations/brave/tools.ts` -- Line 12

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@nbouliol nbouliol force-pushed the feat/ai-tools-integrations branch from 4dd7990 to f4f1525 Compare March 25, 2026 16:31
@nbouliol nbouliol force-pushed the feat/ai-tools-integrations branch from f4f1525 to f4aa7a3 Compare March 25, 2026 16:49

export default class McpConfigChecker {
static check(mcpConfig: McpConfiguration) {
static isForestIntegrationConfig(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

could be private


try {
const json = await response.json();
errorMessage = json.error || json.title || json.description || errorMessage;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 High zendesk/utils.ts:22

assertResponseOk extracts json.error directly into the error message, but the API can return { error: { title: '...' } }. When json.error is an object, string interpolation produces [object Object], discarding the actual error details. The sibling function validateZendeskConfig handles this correctly with json.error?.title.

-      errorMessage = json.error || json.title || json.description || errorMessage;
+      errorMessage = json.error?.title || json.error || json.title || json.description || errorMessage;
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file packages/ai-proxy/src/integrations/zendesk/utils.ts around line 22:

`assertResponseOk` extracts `json.error` directly into the error message, but the API can return `{ error: { title: '...' } }`. When `json.error` is an object, string interpolation produces `[object Object]`, discarding the actual error details. The sibling function `validateZendeskConfig` handles this correctly with `json.error?.title`.

Evidence trail:
packages/ai-proxy/src/integrations/zendesk/utils.ts lines 16-28 (assertResponseOk) and lines 30-46 (validateZendeskConfig) at REVIEWED_COMMIT. Line 22 uses `json.error` directly, while line 40 correctly uses `json.error?.title` to extract nested error details.

) {}

async getConfiguration(): Promise<McpConfiguration> {
async getConfiguration(): Promise<Record<string, ToolConfig>> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👌

Enki Pontvianne and others added 16 commits March 31, 2026 15:12
Decouple Router from McpClient/IntegrationClient by introducing a
ToolProvider interface. Router now receives ToolProvider[] instead of
raw configs, and a factory handles the MCP vs integration split.

- Add ToolProvider interface (loadTools, checkConnection, dispose)
- Add createToolProviders factory to split configs
- McpClient/IntegrationClient implement ToolProvider
- Router accepts toolProviders[] instead of mcpConfigs
- McpConfigChecker uses factory instead of manual type guard
- Fix McpClient.loadTools() tool accumulation bug
- Fix validateZendeskConfig response.json() before response.ok check
- Clean McpConfiguration type (remove ForestIntegrationConfig union)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The class no longer has any MCP-specific logic — it delegates to the
ToolProvider factory. The new name reflects its actual responsibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use Parameters<AiRouter['route']>[0] from agent-toolkit instead of
maintaining a local copy that can diverge silently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
alban bertolini and others added 13 commits March 31, 2026 15:14
Internal lib, no need for backward compat shim.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ider

RemoteTools was both an aggregator and a Brave tool factory. Now Brave
is a ToolProvider like McpClient and IntegrationClient. RemoteTools
becomes a pure container.

- Add BraveToolProvider implementing ToolProvider
- Router creates BraveToolProvider from localToolsApiKeys
- Simplify RemoteTools constructor (no more apiKeys)
- Remove getIntegratedTools dispatcher (no longer needed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename class IntegrationClient → ForestIntegrationClient
- Rename file integration-client.ts → forest-integration-client.ts
- Move isForestIntegrationConfig guard to forest-integration-client.ts
  (colocated with the type it discriminates)
- Update all imports and test mocks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The refactoring to ToolProvider silently dropped dispose error logging.
Inspect Promise.allSettled results and log rejected settlements to
prevent silent resource leaks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The test was passing { configs: { server1: ... } } (wrapped) but the
type now expects Record<string, ToolConfig> (flat).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@nbouliol nbouliol force-pushed the feat/ai-tools-integrations branch from e0bf102 to 402767a Compare March 31, 2026 13:16
@nbouliol nbouliol merged commit 6181114 into main Mar 31, 2026
29 checks passed
@nbouliol nbouliol deleted the feat/ai-tools-integrations branch March 31, 2026 13:43
forest-bot added a commit that referenced this pull request Mar 31, 2026
forest-bot added a commit that referenced this pull request Mar 31, 2026
# @forestadmin/ai-proxy [1.7.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/ai-proxy@1.6.3...@forestadmin/ai-proxy@1.7.0) (2026-03-31)

### Features

* **ai-proxy:** add forest connectors ([#1505](#1505)) ([6181114](6181114))

### Dependencies

* **@forestadmin/agent-toolkit:** upgraded to 1.2.0
* **@forestadmin/datasource-toolkit:** upgraded to 1.53.1
forest-bot added a commit that referenced this pull request Mar 31, 2026
# @forestadmin/forestadmin-client [1.38.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/forestadmin-client@1.37.19...@forestadmin/forestadmin-client@1.38.0) (2026-03-31)

### Features

* **ai-proxy:** add forest connectors ([#1505](#1505)) ([6181114](6181114))

### Dependencies

* **@forestadmin/ai-proxy:** upgraded to 1.7.0
* **@forestadmin/datasource-toolkit:** upgraded to 1.53.1
forest-bot added a commit that referenced this pull request Mar 31, 2026
# @forestadmin/agent [1.76.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent@1.75.2...@forestadmin/agent@1.76.0) (2026-03-31)

### Features

* **ai-proxy:** add forest connectors ([#1505](#1505)) ([6181114](6181114))

### Dependencies

* **@forestadmin/agent-toolkit:** upgraded to 1.2.0
* **@forestadmin/datasource-customizer:** upgraded to 1.69.2
* **@forestadmin/datasource-toolkit:** upgraded to 1.53.1
* **@forestadmin/forestadmin-client:** upgraded to 1.38.0
* **@forestadmin/mcp-server:** upgraded to 1.8.11
* **@forestadmin/datasource-sql:** upgraded to 1.17.10
forest-bot added a commit that referenced this pull request Mar 31, 2026
# @forestadmin/agent-testing [1.1.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent-testing@1.0.25...@forestadmin/agent-testing@1.1.0) (2026-03-31)

### Features

* **ai-proxy:** add forest connectors ([#1505](#1505)) ([6181114](6181114))

### Dependencies

* **@forestadmin/agent-client:** upgraded to 1.4.16
* **@forestadmin/datasource-customizer:** upgraded to 1.69.2
* **@forestadmin/datasource-toolkit:** upgraded to 1.53.1
* **@forestadmin/forestadmin-client:** upgraded to 1.38.0
* **@forestadmin/agent:** upgraded to 1.76.0
* **@forestadmin/datasource-sql:** upgraded to 1.17.10
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.

2 participants