下一级Google Apps脚本开发

摘要
本文介绍了一种在本地开发和测试Google Apps Script(GAS)的强大方法。通过利用 gas-fakes 库,您可以构建一个安全的本地模型上下文协议(MCP)服务器,从而无需部署到云端即可为Google Workspace自动化创建AI驱动的工具。
引言
假冒天然气由Bruce McPherson开发的是一个创新的库,它通过将GAS类和方法替换为相应的Google API,使Google Apps Script(GAS)代码能够直接在本地环境中运行。
该库的引入为GAS开发带来了新的可能性。利用 gas-fakes,我探索了以下技术进步:
- 一个安全的天然气沙箱:我报告了创建一个安全沙箱的可行性,该沙箱允许通过有意限制运行时可用的类和方法来安全执行代码,包括人工智能生成的代码。 参考
- 使用Gemini CLI集成进行动态工具创建:通过整合
gas-fakes随着Gemini CLI--与谷歌Gemini生成式人工智能模型交互的工具——我演示了一种使用谷歌应用脚本为本地模型上下文协议(MCP)服务器动态创建和删除工具的方法。 参考
这些成就表明 gas-fakes 生成式人工智能具有巨大的潜力,可以在确保安全的情况下大幅自动化和简化GAS开发。本文基于这些发现,介绍并演示了一种在本地使用GAS为MCP服务器创建工具的方法,同时确保安全性和无缝授权集成。
通过安装和验证 gas-fakes CLI,开发人员可以从本地环境中的任何目录自由执行GAS代码。此执行始终在安全沙箱中执行。该框架允许使用GAS快速开发MCP服务器的每个工具,并使用安全、无缝的身份验证运行它们。
先决条件和安装
在构建服务器之前,您必须安装并配置必要的命令行工具。
1.安装Gemini CLI
首先,安装 Gemini CLI,它允许与谷歌的Gemini模型进行交互。
npm install -g @google/gemini-cli安装后,按照中的说明授权CLI 官方文件.
2.安装gas fakes命令行界面
接下来,安装 假冒天然气,用于在本地执行Google Apps脚本的命令行工具。
npm install -g @mcpher/gas-fakes如需授权,请咨询官方 入门指南.
3.验证安装
确认 gas-fakes 通过检查CLI的帮助消息,可以正确安装CLI:
gas-fakes --help接下来,通过运行一个简单的脚本来检索Google Drive根文件夹的名称,以测试您的授权:
gas-fakes -s "const rootFolder = DriveApp.getRootFolder(); const rootFolderName = rootFolder.getName(); console.log(rootFolderName);"如果该命令成功打印文件夹名称,则表示您的安装和身份验证工作正常。
构建MCP服务器
安装了这些工具后,您现在可以构建本地MCP服务器。
1.设置项目目录
为您的项目创建一个工作目录,并为MCP服务器安装所需的Node.js模块。
mkdir sample
cd sample
npm install @modelcontextprotocol/sdk zod本指南中的所有后续文件都将在此文件中创建 sample 目录。
2.创建Google Apps脚本工具
这些JavaScript文件将作为MCP服务器的独立工具。
从电子表格中获取工作表名称
创建 get_sheet_names.js:
/**
* Gets sheet names from a Google Spreadsheet.
* @param {Object} object
*/
function myFunction(object = {}) {
if (object.spreadsheetId) {
const spreadsheet = SpreadsheetApp.openById(object.spreadsheetId);
const sheetNames = spreadsheet.getSheets().map((sheet) => sheet.getName());
console.log(sheetNames);
} else {
console.error("error: Spreadsheet ID was not found.");
}
}
// The variable name "args" is fixed for passing arguments.
myFunction(args);从电子表格中获取值
创建 get_values_from_sheet.js:
/**
* Gets values from a Google Spreadsheet.
* @param {Object} object
*/
function myFunction(object = {}) {
const { spreadsheetId, sheetName, range } = object;
if (spreadsheetId && sheetName) {
const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
const sheet = spreadsheet.getSheetByName(sheetName);
const values = range
? sheet.getRange(range).getDisplayValues()
: sheet.getDataRange().getDisplayValues();
console.log(values);
} else {
console.error("error: Spreadsheet ID or Sheet name were not found.");
}
}
// The variable name "args" is fixed for passing arguments.
myFunction(args);将值放入电子表格
创建 set_values_to_sheet.js:
/**
* Puts values into a Google Spreadsheet.
* @param {Object} object
*/
function myFunction(object = {}) {
const { spreadsheetId, sheetName, range, values } = object;
if (spreadsheetId && sheetName && values) {
const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
const sheet = spreadsheet.getSheetByName(sheetName);
let rng;
if (range) {
const r = sheet.getRange(range);
rng = sheet.getRange(
r.getRow(),
r.getColumn(),
values.length,
values[0].length
);
} else {
rng = sheet.getRange(
sheet.getLastRow() + 1,
1,
values.length,
values[0].length
);
}
rng.setValues(values);
console.log(
`${JSON.stringify(
values
)} were put from the cell "${rng.getA1Notation()}".`
);
} else {
console.error(
"error: Spreadsheet ID, Sheet name, or values were not found."
);
}
}
// The variable name "args" is fixed for passing arguments.
myFunction(args);3.定义MCP服务器
这两个脚本定义并运行MCP服务器。
首先,创建 mcp-server.js 要初始化服务器,请执行以下操作:
/**
* @license
* Copyright 2025 Tanaike
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { tools } from "./tools.js";
const server = new McpServer({
name: "sample-mcp-server",
version: "0.0.1",
});
if (tools.length > 0) {
for (const { name, schema, func } of tools) {
server.registerTool(name, schema, func);
}
}
const transport = new StdioServerTransport();
await server.connect(transport);接下来,创建 tools.js 通过定义工具、它们的模式以及执行它们的逻辑 gas-fakes CLI。
import { z } from "zod";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
async function __gas_fakes({ cliArgs, functionArgs }) {
try {
if (Object.keys(functionArgs).length > 0) {
cliArgs.push(
`-a '${JSON.stringify(functionArgs).replace(/\\\\'|'/g, "'\\''")}'`
);
}
const command = `gas-fakes ${cliArgs.join(" ")}`;
const { stdout } = await execAsync(command);
return {
content: [{ type: "text", text: stdout || "Execution finished." }],
isError: false,
};
} catch (err) {
return {
content: [{ type: "text", text: err.message }],
isError: true,
};
}
}
export const tools = [
{
name: "get_sheet_names",
schema: {
description:
"Use this to get the sheet names of all sheets in a Google Spreadsheet.",
inputSchema: { spreadsheetId: z.string().describe("Spreadsheet ID.") },
},
func: async (functionArgs = {}) => {
const scriptFile = "get_sheet_names.js";
// Arguments for the gas-fakes CLI. Use `gas-fakes --help` for more options.
const obj = {
cliArgs: [
`-f "${scriptFile}"`,
"-x",
`-w "${functionArgs.spreadsheetId}"`,
],
functionArgs,
};
return await __gas_fakes(obj);
},
},
{
name: "get_values_from_sheet",
schema: {
description:
"Use this to get values from a specific sheet in a Google Spreadsheet.",
inputSchema: {
spreadsheetId: z.string().describe("Spreadsheet ID."),
sheetName: z.string().describe("Sheet name of a Google Spreadsheet."),
range: z.string().describe("Cell range as A1Notation.").optional(),
},
},
func: async (functionArgs = {}) => {
const scriptFile = "get_values_from_sheet.js";
const obj = {
cliArgs: [
`-f "${scriptFile}"`,
"-x",
`-w "${functionArgs.spreadsheetId}"`,
],
functionArgs,
};
return await __gas_fakes(obj);
},
},
{
name: "set_values_to_sheet",
schema: {
description:
"Use this to put values in a specific sheet in a Google Spreadsheet.",
inputSchema: {
spreadsheetId: z.string().describe("Spreadsheet ID."),
sheetName: z.string().describe("Sheet name of a Google Spreadsheet."),
range: z
.string()
.describe("Cell range as A1Notation. Optional for appending values.")
.optional(),
values: z
.array(z.array(z.union([z.number(), z.string()])))
.describe("Values to put into the cells."),
},
},
func: async (functionArgs = {}) => {
const scriptFile = "set_values_to_sheet.js";
const obj = {
cliArgs: [
`-f "${scriptFile}"`,
"-x",
`--ww "${functionArgs.spreadsheetId}"`,
],
functionArgs,
};
return await __gas_fakes(obj);
},
},
];配置并运行服务器
最后,配置Gemini CLI以识别您的新MCP服务器。
1.配置Gemini CLI
创建一个 settings.json 文件内 .gemini 项目文件夹中的目录。
mkdir .gemini
cd .gemini
echo '{"security":{"auth":{"selectedType":"gemini-api-key"}},"ui":{"theme":"Default"},"mcpServers":{"sample":{"command":"node","args":["mcp-server.js"]}}}' > settings.json
cd ..注: 如果您的Gemini CLI授权方法不是 gemini-api-key,请相应地更新此文件。
2.发射和测试
在您的计算机中启动Gemini CLI sample 目录:
gemini启动后,列出可用的MCP服务器以确认您的服务器已注册:
/mcp你应该看看 sample-mcp-server 上市的。如果没有,请查看前面的步骤是否有错误。

使用示例
要测试这些工具,请创建一个新的谷歌电子表格,添加一些示例数据,并在以下提示中使用其ID。
1.获取工作表名称
提示: (替换 ### 使用您的电子表格ID)
Get sheet names from a Google Spreadsheet. Spreadsheet ID is `###`.
2.从表格中获取值
提示: (替换 ### 使用您的电子表格ID)
Get values from the "Sheet1" sheet. Spreadsheet ID is `###`.
3.将值放入表中
提示: (替换 ### 使用您的电子表格ID)
Put values in the cell "B2" of the "Sheet1" sheet. Spreadsheet ID is `###`. Values are `[["sample1", "sample2", "sample3"],["sample4", "sample5", "sample6"]]`.
结论与未来展望
本文演示了可以使用Google Apps Script成功构建本地MCP服务器,但这种方法广泛适用于其他本地开发场景。虽然为了清楚起见,这里的脚本是手动创建的,但同样的方法可用于构建Gemini CLI扩展,进一步自动化工作流程。
这 gas-fakes 图书馆正在积极发展。虽然并非所有GAS类和方法都可用,但现有的功能集足够强大,可以在本地创建和测试各种Google Apps脚本。如 gas-fakes 随着技术的成熟,它将成为管理谷歌工作区和开发强大的人工智能驱动自动化的越来越不可或缺的工具。
总结
- 地方发展: 这
gas-fakes该库支持本地执行Google Apps脚本,从而在开发和测试期间无需进行云部署。 - 安全沙盒: 所有本地执行都发生在一个安全的沙箱中,确保脚本(包括人工智能生成的脚本)在有限和安全的权限下运行。
- AI工具集成: 您可以构建一个本地MCP服务器,为Gemini等模型创建自定义的AI驱动工具,以便与Google Workspace进行交互。
- 分步指南: 本文提供了设置本地服务器的完整演练,从安装CLI工具到定义和运行基于GAS的工具。
- 简化自动化: 这种方法大大加快了为谷歌表格和其他工作区应用程序创建复杂的、人工智能驱动的自动化的开发生命周期。大大加快了为谷歌表格和其他工作区应用程序创建复杂的、人工智能驱动的自动化的开发生命周期。
