-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Composio Tool Router integration with Google Sheets #142
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
- Use x-api-key auth instead of account_id in request bodies/params - Add Zod validation for disconnect connector endpoint - Move DELETE to /api/connectors (KISS - RESTful design) - Extract getFrontendBaseUrl to own file (SRP) - Simplify registerComposioTools to return raw tools - Filter Composio tools to allowed subset in getTools.ts - Update CLAUDE.md with auth guidelines
…mcp/tools/index.ts
…point - Create validateAuthorizeConnectorBody.ts with Zod schema - Validate connector (required string) and callback_url (optional URL) - Update route to use validation function per coding guidelines
- Add verifyConnectorOwnership() to check connected_account_id belongs to user - DELETE /api/connectors now returns 403 if user doesn't own the connection - Prevents authorization bypass where users could disconnect other users' connectors
- Remove unsafe type assertion 'as Record<string, ComposioTool>' - Add isComposioTool() type guard with runtime validation - Use Object.prototype.hasOwnProperty for safe property access - Validates description (string), inputSchema (exists), execute (function) Addresses CodeRabbit's critical issue about unsafe type casting on SDK return values.
- Replace custom ComposioTool interface with Vercel AI SDK's Tool type - Import Tool and ToolSet types from 'ai' package - Update isValidTool() to check for 'parameters' (SDK format) instead of 'inputSchema' - Use ToolSet as return type for getComposioTools() - Maintains runtime validation while using correct SDK types This aligns with Tool Router's actual return type when using VercelProvider: session.tools() returns ToolSet (Record<string, Tool>) from Vercel AI SDK.
- Check for VERCEL_URL to support preview deployments - Preview URLs need https:// prepended (VERCEL_URL doesn't include protocol) - Maintains production (chat.recoupable.com) and local (localhost:3001) behavior Fixes OAuth redirect issue where preview deployments would incorrectly redirect to localhost, which is unreachable.
- Check VERCEL_GIT_COMMIT_REF for 'test' branch specifically - Use stable test frontend URL for test deployments - Maintains preview URL fallback for other feature branches - Easier to update TEST_FRONTEND_URL constant if domain changes
Match API pattern: test-recoup-api -> test-recoup-chat
- Remove verbose description constant and inline it - Remove separate schema type definition - Inline schema directly in registerTool call - Keep same functionality: passes raw results from getComposioTools - Tool filtering handled by ALLOWED_TOOLS in getTools.ts
- Remove getToolResultSuccess and getToolResultError wrapper imports - Use getCallToolResult(JSON.stringify(...)) directly - Follows KISS: pass raw results without unnecessary wrappers
- Frontend (Recoup-Chat) runs on port 3000, not 3001 - API (Recoup-API) runs on port 3001 - getFrontendBaseUrl should return frontend port
- Remove JSDoc comments - Remove try/catch wrapper - Simplify description and schema - Just pass through results from getComposioTools directly
- Add ENABLED_TOOLKITS constant for easy expansion later - Pass toolkits option to session.create() per Composio docs - Currently only googlesheets is enabled
- Remove account_id from composio tool input schema - Get accountId from MCP auth info via resolveAccountId - Keep room_id as optional input for OAuth redirect - Follows API auth pattern used by other MCP tools
- Update CLAUDE.md Authentication section - Add MCP tools pattern using resolveAccountId - Clarify both API keys and Privy tokens resolve to accountId
…Router directly - Remove googleSheetsAgent and related files - Remove MCP composio wrapper tool - Add Composio tools directly in setupToolsForRequest - Fix tool validation to check for inputSchema (Composio format) - Fix frontend callback URL for local development (localhost:3001)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
rollback changes to this file.
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.
Additional Suggestion:
Missing null/undefined check before using the 'in' operator on session.tools() result causes TypeError if the Composio API returns null or undefined
View Details
📝 Patch Details
diff --git a/lib/composio/toolRouter/getTools.ts b/lib/composio/toolRouter/getTools.ts
index 3d71342..2c66191 100644
--- a/lib/composio/toolRouter/getTools.ts
+++ b/lib/composio/toolRouter/getTools.ts
@@ -58,6 +58,11 @@ export async function getComposioTools(
// Filter to only allowed tools with runtime validation
const filteredTools: ToolSet = {};
+ // Check if allTools is a valid object before using the 'in' operator
+ if (!allTools || typeof allTools !== "object") {
+ return filteredTools;
+ }
+
for (const toolName of ALLOWED_TOOLS) {
if (toolName in allTools) {
const tool = (allTools as Record<string, unknown>)[toolName];
Analysis
Bug Analysis
Why it happens:
The getComposioTools function in lib/composio/toolRouter/getTools.ts calls session.tools() and immediately uses the result with the in operator without validating it. In JavaScript, the in operator requires its right operand to be an object. If session.tools() returns null or undefined, the code throws a TypeError: "Cannot use 'in' operator to search for [toolName] in null/undefined".
When it manifests:
This error could occur in several scenarios:
- Network failures when calling the Composio API
- Unexpected API responses from Composio
- Session creation failures that return an invalid session object
- API changes or library bugs in Composio that return null instead of an object
While Composio likely returns a valid object in normal operation, defensive programming requires handling these edge cases, especially for external API calls.
Impact:
- Runtime TypeError crash that would terminate the chat request
- User's chat would fail to load tools
- Application would return a 500 error to the client
- No graceful fallback to continue chat without Composio tools
Fix Applied
Added a null/undefined check immediately after calling session.tools():
// Check if allTools is a valid object before using the 'in' operator
if (!allTools || typeof allTools !== "object") {
return filteredTools;
}This check:
- Validates that
allToolsis not null or undefined - Ensures it's actually an object type
- Returns an empty ToolSet (which is the correct type) if validation fails
- Prevents the TypeError while maintaining proper behavior
The fix is safe because:
- An empty ToolSet is a valid return value
- It allows the chat to continue without Composio tools rather than crashing
- The existing code already handles empty objects correctly (the loop just doesn't execute)
- It's consistent with defensive programming practices for external API calls
Resolve conflicts in setupToolsForRequest.ts by combining: - HTTP MCP transport (from test) for proper auth - Composio tool router (from composio-tool-router) for Google Sheets and other connectors Updated tests to reflect the new HTTP MCP + Composio architecture. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Changes
Related