diff --git a/workspace-server/src/__tests__/services/SheetsService.test.ts b/workspace-server/src/__tests__/services/SheetsService.test.ts index ac5fc7fd..498d4585 100644 --- a/workspace-server/src/__tests__/services/SheetsService.test.ts +++ b/workspace-server/src/__tests__/services/SheetsService.test.ts @@ -41,6 +41,7 @@ describe('SheetsService', () => { get: jest.fn(), values: { get: jest.fn(), + update: jest.fn(), }, }, }; @@ -432,4 +433,52 @@ describe('SheetsService', () => { expect(response.error).toBe('Metadata Error'); }); }); + + describe('insertText', () => { + it('should insert text into a specific cell', async () => { + const mockResponse = { + data: { + spreadsheetId: 'test-id', + updatedRange: 'Sheet1!A1', + updatedCells: 1, + }, + }; + + mockSheetsAPI.spreadsheets.values.update.mockResolvedValue(mockResponse); + + const result = await sheetsService.insertText({ + spreadsheetId: 'test-id', + range: 'Sheet1!A1', + value: 'Hello', + }); + + expect(mockSheetsAPI.spreadsheets.values.update).toHaveBeenCalledWith({ + spreadsheetId: 'test-id', + range: 'Sheet1!A1', + valueInputOption: 'USER_ENTERED', + requestBody: { + values: [['Hello']], + }, + }); + + const response = JSON.parse(result.content[0].text); + expect(response.updatedRange).toBe('Sheet1!A1'); + expect(response.updatedCells).toBe(1); + }); + + it('should handle errors gracefully', async () => { + mockSheetsAPI.spreadsheets.values.update.mockRejectedValue( + new Error('API Error'), + ); + + const result = await sheetsService.insertText({ + spreadsheetId: 'test-id', + range: 'A1', + value: 'test', + }); + + const response = JSON.parse(result.content[0].text); + expect(response.error).toBe('API Error'); + }); + }); }); diff --git a/workspace-server/src/index.ts b/workspace-server/src/index.ts index e2666a41..4ae67042 100644 --- a/workspace-server/src/index.ts +++ b/workspace-server/src/index.ts @@ -57,7 +57,7 @@ const SCOPES = [ 'https://www.googleapis.com/auth/gmail.modify', 'https://www.googleapis.com/auth/directory.readonly', 'https://www.googleapis.com/auth/presentations.readonly', - 'https://www.googleapis.com/auth/spreadsheets.readonly', + 'https://www.googleapis.com/auth/spreadsheets', ]; // Dynamically import version from package.json @@ -499,6 +499,26 @@ async function main() { sheetsService.getMetadata, ); + server.registerTool( + 'sheets.insertText', + { + description: + 'Inserts text or a value into a specific cell or range in a Google Sheets spreadsheet.', + inputSchema: { + spreadsheetId: z + .string() + .describe('The ID or URL of the spreadsheet to modify.'), + range: z + .string() + .describe( + 'The A1 notation range to insert text into (e.g., "Sheet1!A1").', + ), + value: z.string().describe('The text or value to insert.'), + }, + }, + sheetsService.insertText, + ); + server.registerTool( 'drive.search', { diff --git a/workspace-server/src/services/SheetsService.ts b/workspace-server/src/services/SheetsService.ts index fb8df36f..6b668e66 100644 --- a/workspace-server/src/services/SheetsService.ts +++ b/workspace-server/src/services/SheetsService.ts @@ -310,4 +310,59 @@ export class SheetsService { }; } }; + + public insertText = async ({ + spreadsheetId, + range, + value, + }: { + spreadsheetId: string; + range: string; + value: string; + }) => { + logToFile( + `[SheetsService] Starting insertText for spreadsheet: ${spreadsheetId}, range: ${range}`, + ); + try { + const id = extractDocId(spreadsheetId) || spreadsheetId; + + const sheets = await this.getSheetsClient(); + const response = await sheets.spreadsheets.values.update({ + spreadsheetId: id, + range: range, + valueInputOption: 'USER_ENTERED', + requestBody: { + values: [[value]], + }, + }); + + logToFile(`[SheetsService] Finished insertText for spreadsheet: ${id}`); + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify({ + spreadsheetId: response.data.spreadsheetId, + updatedRange: response.data.updatedRange, + updatedCells: response.data.updatedCells, + }), + }, + ], + }; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + logToFile( + `[SheetsService] Error during sheets.insertText: ${errorMessage}`, + ); + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify({ error: errorMessage }), + }, + ], + }; + } + }; }