
一个新的统一的Google Apps Script现在可以同时部署模型上下文协议(MCP)和代理对代理(A2A)网络作为单一服务器,简化了Google Workspace用户的AI模型集成。
生成式AI的快速发展导致了AI模型之间的日益整合,例如模型上下文协议(MCP)和代理对代理(A2A)协议。最近,我发布了MCPApp和A2AApp,它们使用Google Apps Script建立了MCP和A2A网络。参见 和 参见 这种方法为Google Workspace和Google API用户提供了显著的优势,因为它允许无缝授权并直接在应用程序中集成这些资源。
传统上,分别部署MCP和A2A服务器需要设置和开发两个独立的项目。本报告通过提出一个统一脚本解决了这种低效问题,该脚本能够创建一个集成的服务器,同时支持MCP和A2A服务器。这种整合使得MCP和A2A客户端都能够访问同一个服务器,从而简化操作。此外,它还促进了MCP和A2A服务器之间共享通用函数,大大降低了开发成本并提高了整体效率。
流程图如下所示。
flowchart TD
subgraph 服务器
direction TB
函数[函数] --> mvp[MCP服务器] & a2a[A2A服务器]
end
A[MCP客户端] -- MCP协议 --> 服务器
B[A2A客户端] -- A2A协议 --> 服务器
为了使用本报告中的脚本,请使用您的API密钥。参见 此API密钥用于访问Gemini API。
您可以使用以下Google Apps Script复制演示脚本。请将以下脚本复制并粘贴到Google Apps Script的脚本编辑器中,并运行函数myFunction。这样,演示的Google Apps Script项目就会被复制到您的Google云端硬盘根目录下。
function myFunction() {
const fileId = "1N1eg3vEgi_eVAiPB1SrPG9NIfEEQ5qohZED9haQQ7VbOKnMfLkPkYkUe";
const file = DriveApp.getFileById(fileId);
file.makeCopy(file.getName());
}
当然,您也可以直接从仓库复制并粘贴脚本。GitHub
为了允许MCP和A2A客户端访问,该项目使用了由Google Apps Script构建的Web应用作为服务器。两个客户端都可以使用HTTP GET和HTTP POST请求访问此服务器。因此,Web应用可以作为一个统一的服务器,集成MCP和A2A的功能。
详细信息可以在官方文档中找到。
请按照以下步骤在脚本编辑器中部署Web应用。
https://script.google.com/macros/s/###/exec。此URL用于MCP客户端和A2A服务器。getRegisteringAgentCardURL(),并在控制台中复制显示的URL。此URL用于A2A客户端。请注意,当您修改用于Web应用的Google Apps Script时,必须将其作为新版本进行修改。 这确保了修改后的脚本会在Web应用中生效。请务必注意这一点。您还可以在我的报告"重新部署Web应用而不更改Web应用的URL的新IDE"中找到更多细节。
当您复制文件后,请打开它。此时脚本编辑器会被打开。请进行以下修改。
apiKey。https://script.google.com/macros/s/###/exec设置为agentCard的URL。此时,请添加查询参数accessKey=sample。因此,URL变为https://script.google.com/macros/s/###/exec?accessKey=sample作为MCP客户端,使用Claude Desktop。参见 在这种情况下,claude_desktop_config.json配置如下。请将https://script.google.com/macros/s/###/exec替换为您自己的Web应用URL。
{
"mcpServers": {
"gas_web_apps": {
"command": "npx",
"args": [
"mcp-remote",
"https://script.google.com/macros/s/###/exec?accessKey=sample"
]
}
}
}
请关闭并重新打开Claude Desktop。结果可以在以下演示中看到。

可以看到,Claude Desktop的MCP客户端可以使用集成了MCP服务器和A2A服务器的Google Apps Script服务器。
作为A2A客户端,使用@a2a-js/sdk。参见 在这种情况下,为了使用@a2a-js/sdk测试脚本,需要修改@a2a-js/sdk。请按如下方式修改node_modules/@a2a-js/sdk/build/src/client/client.js中的_fetchAndCacheAgentCard函数。
为了请求Google Apps Script Web应用的路径/.well-known/agent.json,需要访问令牌参见。此访问令牌用作查询参数。然而,大多数当前的A2A客户端规范不支持这一点。因此,需要进行以下修改。
此外,请求Web应用需要重定向参见。不幸的是,Python的公共A2A客户端不支持重定向。相比之下,Node.js默认支持重定向。出于这些原因,选择了@a2a-js/sdk作为本报告的示例。
从
const agentCardUrl = `${this.agentBaseUrl}/.well-known/agent.json`;
到
const agentCardUrl = ((agentBaseUrl) => {
/**
* ### 描述
* 该方法用于解析包括查询参数的URL。
* 参见:https://tanaikech.github.io/2018/07/12/adding-query-parameters-to-url-using-google-apps-script/
*
* @param {String} url 包括查询参数的URL。
* @return {Object} 包括基础URL和查询参数的JSON对象。
*/
function parseQueryParameters(url) {
if (url === null || typeof url != "string") {
throw new Error(
"请提供包括查询参数的URL(字符串)。"
);
}
const s = url.split("?");
if (s.length == 1) {
return { url: s[0], queryParameters: null };
}
const [baseUrl, query] = s;
if (query) {
const queryParameters = query.split("&").reduce(function (o, e) {
const temp = e.split("=");
const key = temp[0].trim();
let value = temp[1].trim();
value = isNaN(value) ? value : Number(value);
if (o[key]) {
o[key].push(value);
} else {
o[key] = [value];
}
return o;
}, {});
return { url: baseUrl, queryParameters };
}
return null;
}
/**
* ### 描述
* 该方法用于向URL添加查询参数。
* 参见:https://tanaikech.github.io/2018/07/12/adding-query-parameters-to-url-using-google-apps-script/
*
* @param {String} url 添加查询参数的基础URL。
* @param {Object} obj 包括查询参数的JSON对象。
* @return {String} 包括查询参数的URL。
*/
function addQueryParameters(url, obj) {
if (url === null || obj === null || typeof url != "string") {
throw new Error(
"请提供URL(字符串)和查询参数(JSON对象)。"
);
}
const o = Object.entries(obj);
return (
(url == "" ? "" : `${url}${o.length > 0 ? "?" : ""}`) +
o
.flatMap(([k, v]) =>
Array.isArray(v)
? v.map((e) => `${k}=${encodeURIComponent(e)}`)
: `${k}=${encodeURIComponent(v)}`
)
.join("&")
);
}
const urlObj = parseQueryParameters(agentBaseUrl);
return addQueryParameters(
`${urlObj.url}/.well-known/agent.json`,
urlObj.queryParameters
);
})(this.agentBaseUrl);
A2A客户端的示例脚本如下。请将https://script.google.com/macros/s/###/dev?access_token=###&accessKey=sample替换为您通过复制的脚本中的函数getRegisteringAgentCardURL()获取的URL。
import {
A2AClient,
Message,
MessageSendParams,
SendMessageResponse,
SendMessageSuccessResponse,
} from "@a2a-js/sdk";
import { v4 as uuidv4 } from "uuid";
// 请设置您的A2A服务器URL。
const agentBaseUrl = "https://script.google.com/macros/s/###/dev?access_token=###&accessKey=sample";
// 用于测试上述A2A服务器的示例提示。
const prompts = [
"10日元等于多少美元?",
"今天中午东京的天气预报是什么?",
];
async function run(prompts: Array<string>) {
const client = new A2AClient(agentBaseUrl);
for (let prompt of prompts) {
const messageId = uuidv4();
const sendParams: MessageSendParams = {
message: {
messageId: messageId,
role: "user",
parts: [{ kind: "text", text: prompt }],
kind: "message",
},
configuration: {
blocking: true,
acceptedOutputModes: ["text/plain"],
},
};
const sendResponse: SendMessageResponse = await client.sendMessage(
sendParams
);
const result = (sendResponse as SendMessageSuccessResponse).result;
const messageResult = result as Message;
messageResult.parts.forEach((e) => {
if (e.kind == "text") {
console.log(`提示:${prompt}`);
console.log(`响应:${e.text}`);
}
});
}
}
run(prompts);
当运行此脚本时,可以获得以下结果。

可以看到,由@a2a-js/sdk创建的A2A客户端可以使用集成了MCP服务器和A2A服务器的Google Apps Script服务器。
@a2a-js/sdk作为A2A客户端的演示成功地展示了,集成的Google Apps Script服务器对于这两种协议都能正确工作。<a name="licence"></a>
<a name="author"></a>
<a name="updatehistory"></a>
v1.0.0 (2025年6月19日)