-
Couldn't load subscription status.
- Fork 2
feat(toolsets): add multi-account support for fetchTools #118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add support for fetching tools from multiple accounts via MCP: - Add `setAccounts()` method to configure default account IDs - Add `FetchToolsOptions.accountIds` to specify accounts per fetch - Options override `setAccounts()` when both provided - Each account gets separate MCP session with `x-account-id` header - Tools from all accounts are merged into single collection Tests: - Mock MCP server now respects `x-account-id` header - Test account-specific tool filtering - Test `setAccounts()` and `fetchTools()` override behavior - Verify tools from multiple accounts are correctly merged Related: unified-cloud-api MCP endpoint uses x-account-id header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds multi-account support to the StackOne toolset's fetchTools functionality. It enables fetching tools from multiple StackOne accounts simultaneously through the Model Context Protocol (MCP).
- Implements
setAccounts()method for setting default account IDs andFetchToolsOptions.accountIdsfor per-call account specification - Modifies the MCP session handling to use separate sessions per account with
x-account-idheaders - Updates the mock test server to handle account-specific tool filtering and adds comprehensive test coverage
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/toolsets/stackone.ts | Adds multi-account support with setAccounts() method and account-aware fetchTools() implementation |
| src/toolsets/tests/stackone.mcp-fetch.spec.ts | Updates mock server for account-based tool filtering and adds comprehensive test suite for multi-account functionality |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| const headers = { 'x-account-id': accountId }; | ||
| const mergedHeaders = { ...this.headers, ...headers }; | ||
|
|
||
| // Create a temporary toolset instance with the account-specific headers | ||
| const tempHeaders = mergedHeaders; | ||
| const originalHeaders = this.headers; | ||
| this.headers = tempHeaders; | ||
|
|
||
| try { | ||
| const tools = await super.fetchTools(); | ||
| return tools.toArray(); | ||
| } finally { | ||
| // Restore original headers | ||
| this.headers = originalHeaders; | ||
| } |
Copilot
AI
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modifying the instance's headers property during async operations creates a race condition. If multiple fetchTools calls run concurrently, they will overwrite each other's headers. Consider passing headers as a parameter to the parent method or creating a separate client instance for each account.
| const headers = { 'x-account-id': accountId }; | |
| const mergedHeaders = { ...this.headers, ...headers }; | |
| // Create a temporary toolset instance with the account-specific headers | |
| const tempHeaders = mergedHeaders; | |
| const originalHeaders = this.headers; | |
| this.headers = tempHeaders; | |
| try { | |
| const tools = await super.fetchTools(); | |
| return tools.toArray(); | |
| } finally { | |
| // Restore original headers | |
| this.headers = originalHeaders; | |
| } | |
| // Create a new instance of this toolset with account-specific headers | |
| const accountHeaders = { ...this.headers, 'x-account-id': accountId }; | |
| // Clone the config for the new instance | |
| const config = { | |
| ...this.config, | |
| apiKey: this.config.apiKey, | |
| accountId: accountId, | |
| strict: this.config.strict, | |
| removedParams: this.config.removedParams, | |
| }; | |
| // Create a new instance of the current class (assume constructor signature is (config)) | |
| const ToolSetClass = this.constructor as typeof ToolSet; | |
| const toolsetInstance = new ToolSetClass({ | |
| ...config, | |
| headers: accountHeaders, | |
| }); | |
| const tools = await toolsetInstance.fetchTools(); | |
| return tools.toArray(); |
| @@ -1,5 +1,5 @@ | |||
| import { loadStackOneSpecs } from '../openapi/loader'; | |||
| import { StackOneTool, type Tools } from '../tool'; | |||
| import { StackOneTool, Tools } from '../tool'; | |||
Copilot
AI
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import statement removes the 'type' keyword from Tools import. This changes Tools from a type-only import to a runtime import, which could affect bundle size and tree-shaking. Consider keeping it as 'type Tools' if Tools is only used for type annotations.
| import { StackOneTool, Tools } from '../tool'; | |
| import { StackOneTool } from '../tool'; | |
| import type { Tools } from '../tool'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
| _meta: undefined, | ||
| }) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
u ok with Mock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 2 files
Prompt for AI agents (all 1 issues)
Understand the root cause of the following 1 issues and fix them.
<file name="src/toolsets/stackone.ts">
<violation number="1" location="src/toolsets/stackone.ts:150">
Running account fetches in parallel while mutating this.headers causes later iterations to overwrite the header used by earlier requests, so tools fetched for one account inherit another account's MCP session headers. Please avoid mutating shared headers during concurrent fetches (e.g., clone the toolset or run the fetches sequentially).</violation>
</file>
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
| // Create a temporary toolset instance with the account-specific headers | ||
| const tempHeaders = mergedHeaders; | ||
| const originalHeaders = this.headers; | ||
| this.headers = tempHeaders; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running account fetches in parallel while mutating this.headers causes later iterations to overwrite the header used by earlier requests, so tools fetched for one account inherit another account's MCP session headers. Please avoid mutating shared headers during concurrent fetches (e.g., clone the toolset or run the fetches sequentially).
Prompt for AI agents
Address the following comment on src/toolsets/stackone.ts at line 150:
<comment>Running account fetches in parallel while mutating this.headers causes later iterations to overwrite the header used by earlier requests, so tools fetched for one account inherit another account's MCP session headers. Please avoid mutating shared headers during concurrent fetches (e.g., clone the toolset or run the fetches sequentially).</comment>
<file context>
@@ -103,6 +115,59 @@ export class StackOneToolSet extends ToolSet {
+ // Create a temporary toolset instance with the account-specific headers
+ const tempHeaders = mergedHeaders;
+ const originalHeaders = this.headers;
+ this.headers = tempHeaders;
+
+ try {
</file context>
commit: |
Summary
Add support for fetching tools from multiple StackOne accounts via MCP.
Changes
API
setAccounts(accountIds: string[])method to configure default account IDsFetchToolsOptions.accountIds?: string[]to specify accounts per fetch callsetAccounts()when both are providedBehavior
x-account-idheaderTesting
x-account-idheader and returns account-specific toolssetAccounts()andfetchTools()override behaviorUsage
Implementation Notes
This follows the unified-cloud-api MCP endpoint design where:
x-account-idheader)/ai/chat/toolswhich acceptsaccountIds[]in bodyTest Plan
Summary by cubic
Add multi-account support to fetchTools so you can pull tools from multiple StackOne accounts in one call. Each account is fetched via MCP and merged into a single collection.