Skip to content

Commit 6265831

Browse files
fredzqmgoogle-labs-jules[bot]joehan
authored
[FDC MCP] Merge multiple tools into dataconnect_info (#9056)
* Deleted the old files: `list_services.ts`, `get_schema.ts`, and `get_connector.ts`. * feat(dataconnect): merge list, get schema, and get connector tools Merges the `dataconnect_list_services`, `dataconnect_get_connector`, and `dataconnect_get_schema` tools into a single `dataconnect_info` tool. This new tool provides a comprehensive view of all Data Connect services, schemas, and connectors, indicating whether they exist locally, remotely, or both. The output is formatted to prioritize information from the local workspace. * save * save * done * instructions * instructions * rename * changelog * add * m * renmae back to info --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Joe Hanley <[email protected]>
1 parent e183833 commit 6265831

File tree

7 files changed

+153
-101
lines changed

7 files changed

+153
-101
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
- Fixed the bugs when MCP tools cannot connect to emulator due to CLI version mis-matched. (#9068)
44
- Fixed a bug where `firebase dataconnect:sdk:generate --watch` swallowed all logs. (#9055)
55
- Added GA4 agent user property to tag CLI usage by coding agents. (#9070)
6+
- Consolidated Data Connect MCP tools into `dataconnect_info` tool to surface information of local workspace and backend resources. (#9056)

src/dataconnect/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export async function getSchema(serviceName: string): Promise<types.Schema | und
100100
export async function listSchemas(
101101
serviceName: string,
102102
fields: string[] = [],
103-
): Promise<types.Schema[] | undefined> {
103+
): Promise<types.Schema[]> {
104104
const schemas: types.Schema[] = [];
105105
const getNextPage = async (pageToken = "") => {
106106
const res = await dataconnectClient().get<{

src/mcp/tools/dataconnect/get_connector.ts

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/mcp/tools/dataconnect/get_schema.ts

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/mcp/tools/dataconnect/index.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
import type { ServerTool } from "../../tool";
22
import { generate_operation } from "./generate_operation";
33
import { generate_schema } from "./generate_schema";
4-
import { list_services } from "./list_services";
5-
import { get_schema } from "./get_schema";
6-
import { get_connectors } from "./get_connector";
4+
import { info } from "./info";
75
import { compile } from "./compile";
86
import { execute } from "./execute";
97

108
export const dataconnectTools: ServerTool[] = [
119
compile,
12-
list_services,
1310
generate_schema,
1411
generate_operation,
15-
get_schema,
16-
get_connectors,
12+
info,
1713
execute,
1814
];

src/mcp/tools/dataconnect/info.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { z } from "zod";
2+
import * as path from "path";
3+
import { tool } from "../../tool";
4+
import { toContent } from "../../util";
5+
import * as client from "../../../dataconnect/client";
6+
import { loadAll } from "../../../dataconnect/load";
7+
import { Service, Schema, ServiceInfo, Connector } from "../../../dataconnect/types";
8+
import { dump } from "js-yaml";
9+
import { logger } from "../../../logger";
10+
11+
interface CombinedServiceInfo {
12+
local?: ServiceInfo;
13+
deployed?: DeployServiceInfo;
14+
}
15+
16+
interface DeployServiceInfo {
17+
service?: Service;
18+
schemas?: Schema[];
19+
connectors?: Connector[];
20+
}
21+
22+
export const info = tool(
23+
{
24+
name: "info",
25+
description: "Get information about the Firebase Data Connect local and deployed resources.",
26+
inputSchema: z.object({}),
27+
annotations: {
28+
title: "Get information about Firebase Data Connect",
29+
readOnlyHint: true,
30+
},
31+
_meta: {
32+
requiresProject: false,
33+
requiresAuth: false,
34+
},
35+
},
36+
async (_, { projectId, config }) => {
37+
const localServiceInfos = await loadAll(projectId, config);
38+
const serviceInfos = new Map<string, CombinedServiceInfo>();
39+
40+
for (const l of localServiceInfos) {
41+
serviceInfos.set(
42+
`locations/${l.dataConnectYaml.location}/services/${l.dataConnectYaml.serviceId}`,
43+
{ local: l },
44+
);
45+
}
46+
47+
if (projectId) {
48+
try {
49+
const [services, schemas, connectors] = await Promise.all([
50+
client.listAllServices(projectId),
51+
client.listSchemas(`projects/${projectId}/locations/-/services/-`),
52+
client.listConnectors(`projects/${projectId}/locations/-/services/-`),
53+
]);
54+
console.log(services, schemas, connectors);
55+
for (const s of services) {
56+
const k = s.name.split("/").slice(2, 6).join("/");
57+
const st = serviceInfos.get(k) || {};
58+
st.deployed = st.deployed || {};
59+
st.deployed.service = s;
60+
serviceInfos.set(k, st);
61+
}
62+
for (const s of schemas) {
63+
const k = s.name.split("/").slice(2, 6).join("/");
64+
const st = serviceInfos.get(k) || {};
65+
st.deployed = st.deployed || {};
66+
st.deployed.schemas = st.deployed.schemas || [];
67+
st.deployed.schemas.push(s);
68+
serviceInfos.set(k, st);
69+
}
70+
for (const s of connectors) {
71+
const k = s.name.split("/").slice(2, 6).join("/");
72+
const st = serviceInfos.get(k) || {};
73+
st.deployed = st.deployed || {};
74+
st.deployed.connectors = st.deployed.connectors || [];
75+
st.deployed.connectors.push(s);
76+
serviceInfos.set(k, st);
77+
}
78+
} catch (e: any) {
79+
logger.debug("cannot fetch dataconnect resources in the backend", e);
80+
}
81+
}
82+
83+
const localServices = Array.from(serviceInfos.values()).filter((s) => s.local);
84+
const remoteOnlyServices = Array.from(serviceInfos.values()).filter((s) => !s.local);
85+
86+
const output: string[] = [];
87+
88+
function includeDeployedServiceInfo(deployed: DeployServiceInfo): void {
89+
if (deployed.schemas?.length) {
90+
output.push(`### Schemas`);
91+
for (const s of deployed.schemas) {
92+
clearCCFEFields(s);
93+
output.push(dump(s));
94+
}
95+
}
96+
if (deployed.connectors?.length) {
97+
output.push(`### Connectors`);
98+
for (const c of deployed.connectors) {
99+
clearCCFEFields(c);
100+
output.push(dump(c));
101+
}
102+
}
103+
}
104+
105+
if (localServices.length) {
106+
output.push(`# Local Data Connect Sources`);
107+
for (const s of localServices) {
108+
const local = s.local!;
109+
output.push(dump(local.dataConnectYaml));
110+
const schemaDir = path.join(local.sourceDirectory, local.dataConnectYaml.schema.source);
111+
output.push(`You can find all of schema sources under ${schemaDir}/`);
112+
if (s.deployed) {
113+
output.push(`It's already deployed in the backend:\n`);
114+
includeDeployedServiceInfo(s.deployed);
115+
}
116+
}
117+
}
118+
119+
if (remoteOnlyServices.length) {
120+
output.push(`# Data Connect Services in project ${projectId}`);
121+
for (const s of remoteOnlyServices) {
122+
if (s.deployed) {
123+
includeDeployedServiceInfo(s.deployed);
124+
}
125+
}
126+
}
127+
128+
output.push(`\n# What's next?`);
129+
if (!localServices.length) {
130+
output.push(
131+
`- There is no local Data Connect service in the local workspace. Consider use the \`firebase_init\` MCP tool to setup one.`,
132+
);
133+
}
134+
output.push(
135+
`- You can use the \`dataconnect_compile\` tool to compile all local Data Connect schemas and query sources.`,
136+
);
137+
output.push(
138+
`- You run \`firebase deploy\` in command line to deploy the Data Connect schemas, connector and perform SQL migrations.`,
139+
);
140+
return toContent(output.join("\n"));
141+
},
142+
);
143+
144+
function clearCCFEFields(r: any): void {
145+
const fieldsToClear = ["updateTime", "uid", "etag"];
146+
for (const k of fieldsToClear) {
147+
delete r[k];
148+
}
149+
}

src/mcp/tools/dataconnect/list_services.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)