@@ -37,20 +37,63 @@ var (
3737)
3838
3939func init () {
40+ // Meta Ads debug
4041 debugMetaAdsCmd .Flags ().StringVar (& debugMetaPath , "path" , "" , "Graph API path, e.g. me/adaccounts or act_123/campaigns (required)" )
4142 debugMetaAdsCmd .Flags ().StringVar (& debugMetaMethod , "method" , "GET" , "HTTP method: GET or POST" )
4243 debugMetaAdsCmd .Flags ().StringVar (& debugMetaParams , "params" , "" , "JSON object of additional query/body params" )
4344 debugMetaAdsCmd .Flags ().StringVar (& debugMetaPageID , "page-id" , "" , "Use this page's access token instead of user token" )
4445 debugMetaAdsCmd .MarkFlagRequired ("path" )
4546 debugCmd .AddCommand (debugMetaAdsCmd )
4647
47- debugGoogleAdsCmd .Flags ().StringVar (& debugGoogleCustomerID , "customer-id" , "" , "Google Ads customer ID (required)" )
48- debugGoogleAdsCmd .Flags ().StringVar (& debugGoogleLoginCustomerID , "login-customer-id" , "" , "MCC login customer ID (optional)" )
49- debugGoogleAdsCmd .Flags ().StringVar (& debugGoogleGAQL , "gaql" , "" , "GAQL query to execute (required)" )
50- debugGoogleAdsCmd .MarkFlagRequired ("customer-id" )
51- debugGoogleAdsCmd .MarkFlagRequired ("gaql" )
48+ // Google Ads debug subcommands
49+ // gaql
50+ debugGoogleAdsGAQLCmd .Flags ().StringVar (& debugGoogleCustomerID , "customer-id" , "" , "Google Ads customer ID (required)" )
51+ debugGoogleAdsGAQLCmd .Flags ().StringVar (& debugGoogleLoginCustomerID , "login-customer-id" , "" , "MCC login customer ID (optional)" )
52+ debugGoogleAdsGAQLCmd .Flags ().StringVar (& debugGoogleGAQL , "gaql" , "" , "GAQL query to execute (required)" )
53+ debugGoogleAdsGAQLCmd .MarkFlagRequired ("customer-id" )
54+ debugGoogleAdsGAQLCmd .MarkFlagRequired ("gaql" )
55+ debugGoogleAdsCmd .AddCommand (debugGoogleAdsGAQLCmd )
56+
57+ // list-assets
58+ debugGoogleAdsListAssetsCmd .Flags ().StringVar (& debugGoogleCustomerID , "customer-id" , "" , "Google Ads customer ID (required)" )
59+ debugGoogleAdsListAssetsCmd .Flags ().StringVar (& debugGoogleAssetType , "asset-type" , "" , "Filter by asset type (IMAGE, TEXT, YOUTUBE_VIDEO, etc.)" )
60+ debugGoogleAdsListAssetsCmd .Flags ().IntVar (& debugGoogleLimit , "limit" , 0 , "Max assets to return (default: 100)" )
61+ debugGoogleAdsListAssetsCmd .MarkFlagRequired ("customer-id" )
62+ debugGoogleAdsCmd .AddCommand (debugGoogleAdsListAssetsCmd )
63+
64+ // upload-asset
65+ debugGoogleAdsUploadAssetCmd .Flags ().StringVar (& debugGoogleCustomerID , "customer-id" , "" , "Google Ads customer ID (required)" )
66+ debugGoogleAdsUploadAssetCmd .Flags ().StringVar (& debugGoogleAssetType , "asset-type" , "" , "Asset type: IMAGE, TEXT, or YOUTUBE_VIDEO (required)" )
67+ debugGoogleAdsUploadAssetCmd .Flags ().StringVar (& debugGoogleAssetName , "name" , "" , "Friendly name for the asset" )
68+ debugGoogleAdsUploadAssetCmd .Flags ().StringVar (& debugGoogleImageURL , "image-url" , "" , "Public URL of image to upload (for IMAGE type)" )
69+ debugGoogleAdsUploadAssetCmd .Flags ().StringVar (& debugGoogleText , "text" , "" , "Text content (for TEXT type)" )
70+ debugGoogleAdsUploadAssetCmd .Flags ().StringVar (& debugGoogleYouTubeVideoID , "youtube-video-id" , "" , "YouTube video ID (for YOUTUBE_VIDEO type)" )
71+ debugGoogleAdsUploadAssetCmd .MarkFlagRequired ("customer-id" )
72+ debugGoogleAdsUploadAssetCmd .MarkFlagRequired ("asset-type" )
73+ debugGoogleAdsCmd .AddCommand (debugGoogleAdsUploadAssetCmd )
74+
75+ // pmax-asset-groups
76+ debugGoogleAdsPmaxAssetGroupsCmd .Flags ().StringVar (& debugGoogleCustomerID , "customer-id" , "" , "Google Ads customer ID (required)" )
77+ debugGoogleAdsPmaxAssetGroupsCmd .Flags ().StringVar (& debugGoogleCampaignID , "campaign-id" , "" , "Campaign ID (required)" )
78+ debugGoogleAdsPmaxAssetGroupsCmd .MarkFlagRequired ("customer-id" )
79+ debugGoogleAdsPmaxAssetGroupsCmd .MarkFlagRequired ("campaign-id" )
80+ debugGoogleAdsCmd .AddCommand (debugGoogleAdsPmaxAssetGroupsCmd )
81+
82+ // list-customers
83+ debugGoogleAdsCmd .AddCommand (debugGoogleAdsListCustomersCmd )
84+
85+ // tools-list
86+ debugGoogleAdsCmd .AddCommand (debugGoogleAdsToolsListCmd )
87+
88+ // call (generic)
89+ debugGoogleAdsCallCmd .Flags ().StringVar (& debugGoogleToolName , "tool" , "" , "Tool name to call (required)" )
90+ debugGoogleAdsCallCmd .Flags ().StringVar (& debugGoogleToolArgs , "args" , "{}" , "JSON object of tool arguments" )
91+ debugGoogleAdsCallCmd .MarkFlagRequired ("tool" )
92+ debugGoogleAdsCmd .AddCommand (debugGoogleAdsCallCmd )
93+
5294 debugCmd .AddCommand (debugGoogleAdsCmd )
5395
96+ // TikTok Ads debug
5497 debugTikTokAdsCmd .Flags ().StringVar (& debugTikTokAdvertiserID , "advertiser-id" , "" , "TikTok advertiser ID (required)" )
5598 debugTikTokAdsCmd .Flags ().StringVar (& debugTikTokEndpoint , "endpoint" , "" , "TikTok API endpoint path (required)" )
5699 debugTikTokAdsCmd .Flags ().StringVar (& debugTikTokParams , "params" , "{}" , "JSON params for the request" )
@@ -93,22 +136,217 @@ func runDebugMetaAds(cmd *cobra.Command, args []string) error {
93136 return printJSON (result )
94137}
95138
96- // --- Google Ads debug (placeholder - not yet implemented server-side) ---
139+ // --- Google Ads debug via MCP ---
97140
98141var debugGoogleAdsCmd = & cobra.Command {
99142 Use : "google-ads" ,
100- Short : "Send raw GAQL query to Google Ads API" ,
101- RunE : runDebugGoogleAds ,
143+ Short : "Debug Google Ads via MCP (subcommands: gaql, list-customers, list-assets, upload-asset, pmax-asset-groups, tools-list)" ,
144+ Long : `Debug Google Ads MCP server tools.
145+
146+ Subcommands:
147+ gaql Execute a raw GAQL query
148+ list-customers List accessible Google Ads customer accounts
149+ list-assets List assets in a Google Ads account
150+ upload-asset Upload a text/image/video asset
151+ pmax-asset-groups List PMax asset groups for a campaign
152+ tools-list List all available tools on the Google Ads MCP server
153+ call Call any tool by name with JSON args` ,
154+ }
155+
156+ var debugGoogleAdsGAQLCmd = & cobra.Command {
157+ Use : "gaql" ,
158+ Short : "Execute a raw GAQL query via MCP" ,
159+ Long : `Execute a raw GAQL query via the Google Ads MCP server.
160+
161+ Examples:
162+ pipeboard debug google-ads gaql --customer-id 1234567890 --gaql "SELECT campaign.id, campaign.name FROM campaign LIMIT 10"
163+ pipeboard debug google-ads gaql --customer-id 1234567890 --gaql "SELECT asset.id, asset.name, asset.type FROM asset LIMIT 5"` ,
164+ RunE : runDebugGoogleAdsGAQL ,
165+ }
166+
167+ var debugGoogleAdsListCustomersCmd = & cobra.Command {
168+ Use : "list-customers" ,
169+ Short : "List accessible Google Ads customer accounts" ,
170+ RunE : runDebugGoogleAdsListCustomers ,
171+ }
172+
173+ var debugGoogleAdsListAssetsCmd = & cobra.Command {
174+ Use : "list-assets" ,
175+ Short : "List assets in a Google Ads account" ,
176+ Long : `List creative assets in a Google Ads account.
177+
178+ Examples:
179+ pipeboard debug google-ads list-assets --customer-id 1234567890
180+ pipeboard debug google-ads list-assets --customer-id 1234567890 --asset-type IMAGE
181+ pipeboard debug google-ads list-assets --customer-id 1234567890 --asset-type TEXT --limit 20` ,
182+ RunE : runDebugGoogleAdsListAssets ,
183+ }
184+
185+ var debugGoogleAdsUploadAssetCmd = & cobra.Command {
186+ Use : "upload-asset" ,
187+ Short : "Upload an asset (text, image URL, or YouTube video)" ,
188+ Long : `Upload a creative asset to a Google Ads account.
189+
190+ Examples:
191+ pipeboard debug google-ads upload-asset --customer-id 1234567890 --asset-type TEXT --text "Free shipping today"
192+ pipeboard debug google-ads upload-asset --customer-id 1234567890 --asset-type IMAGE --image-url "https://example.com/banner.jpg" --name "My Banner"
193+ pipeboard debug google-ads upload-asset --customer-id 1234567890 --asset-type YOUTUBE_VIDEO --youtube-video-id "dQw4w9WgXcQ"` ,
194+ RunE : runDebugGoogleAdsUploadAsset ,
195+ }
196+
197+ var debugGoogleAdsPmaxAssetGroupsCmd = & cobra.Command {
198+ Use : "pmax-asset-groups" ,
199+ Short : "List PMax asset groups for a campaign" ,
200+ Long : `List Performance Max asset groups for a campaign.
201+
202+ Examples:
203+ pipeboard debug google-ads pmax-asset-groups --customer-id 1234567890 --campaign-id 9876543210` ,
204+ RunE : runDebugGoogleAdsPmaxAssetGroups ,
205+ }
206+
207+ var debugGoogleAdsToolsListCmd = & cobra.Command {
208+ Use : "tools-list" ,
209+ Short : "List all available tools on the Google Ads MCP server" ,
210+ RunE : runDebugGoogleAdsToolsList ,
211+ }
212+
213+ var debugGoogleAdsCallCmd = & cobra.Command {
214+ Use : "call" ,
215+ Short : "Call any Google Ads MCP tool by name" ,
216+ Long : `Call any tool on the Google Ads MCP server with JSON arguments.
217+
218+ Examples:
219+ pipeboard debug google-ads call --tool get_google_ads_campaigns --args '{"customer_id":"1234567890"}'
220+ pipeboard debug google-ads call --tool list_google_ads_assets --args '{"customer_id":"1234567890","asset_type":"IMAGE"}'` ,
221+ RunE : runDebugGoogleAdsCall ,
102222}
103223
104224var (
105225 debugGoogleCustomerID string
106226 debugGoogleLoginCustomerID string
107227 debugGoogleGAQL string
228+ debugGoogleAssetType string
229+ debugGoogleLimit int
230+ debugGoogleText string
231+ debugGoogleImageURL string
232+ debugGoogleYouTubeVideoID string
233+ debugGoogleAssetName string
234+ debugGoogleCampaignID string
235+ debugGoogleToolName string
236+ debugGoogleToolArgs string
108237)
109238
110- func runDebugGoogleAds (cmd * cobra.Command , args []string ) error {
111- return fmt .Errorf ("not yet implemented server-side. Coming soon" )
239+ const googleAdsMCPServer = "google-ads-mcp"
240+
241+ func newGoogleAdsMCPClient () (* client.Client , error ) {
242+ token , err := getToken ()
243+ if err != nil {
244+ return nil , err
245+ }
246+ c := client .New (apiURL , token )
247+ fmt .Fprintf (os .Stderr , "Connecting to %s/%s...\n " , apiURL , googleAdsMCPServer )
248+ if err := c .Initialize (googleAdsMCPServer ); err != nil {
249+ return nil , fmt .Errorf ("MCP handshake failed: %w" , err )
250+ }
251+ return c , nil
252+ }
253+
254+ func callGoogleAdsTool (toolName string , args map [string ]interface {}) error {
255+ c , err := newGoogleAdsMCPClient ()
256+ if err != nil {
257+ return err
258+ }
259+ fmt .Fprintf (os .Stderr , "Calling %s...\n " , toolName )
260+ result , err := c .CallTool (googleAdsMCPServer , toolName , args )
261+ if err != nil {
262+ return fmt .Errorf ("tool call failed: %w" , err )
263+ }
264+ var parsed interface {}
265+ if err := json .Unmarshal (result , & parsed ); err != nil {
266+ fmt .Println (string (result ))
267+ return nil
268+ }
269+ return printJSON (parsed )
270+ }
271+
272+ func runDebugGoogleAdsGAQL (cmd * cobra.Command , args []string ) error {
273+ toolArgs := map [string ]interface {}{
274+ "customer_id" : debugGoogleCustomerID ,
275+ "query" : debugGoogleGAQL ,
276+ }
277+ if debugGoogleLoginCustomerID != "" {
278+ toolArgs ["login_customer_id" ] = debugGoogleLoginCustomerID
279+ }
280+ return callGoogleAdsTool ("execute_google_ads_gaql_query" , toolArgs )
281+ }
282+
283+ func runDebugGoogleAdsListCustomers (cmd * cobra.Command , args []string ) error {
284+ return callGoogleAdsTool ("list_google_ads_customers" , map [string ]interface {}{})
285+ }
286+
287+ func runDebugGoogleAdsListAssets (cmd * cobra.Command , args []string ) error {
288+ toolArgs := map [string ]interface {}{
289+ "customer_id" : debugGoogleCustomerID ,
290+ }
291+ if debugGoogleAssetType != "" {
292+ toolArgs ["asset_type" ] = debugGoogleAssetType
293+ }
294+ if debugGoogleLimit > 0 {
295+ toolArgs ["limit" ] = debugGoogleLimit
296+ }
297+ return callGoogleAdsTool ("list_google_ads_assets" , toolArgs )
298+ }
299+
300+ func runDebugGoogleAdsUploadAsset (cmd * cobra.Command , args []string ) error {
301+ toolArgs := map [string ]interface {}{
302+ "customer_id" : debugGoogleCustomerID ,
303+ "asset_type" : debugGoogleAssetType ,
304+ }
305+ if debugGoogleAssetName != "" {
306+ toolArgs ["name" ] = debugGoogleAssetName
307+ }
308+ if debugGoogleImageURL != "" {
309+ toolArgs ["image_url" ] = debugGoogleImageURL
310+ }
311+ if debugGoogleText != "" {
312+ toolArgs ["text" ] = debugGoogleText
313+ }
314+ if debugGoogleYouTubeVideoID != "" {
315+ toolArgs ["youtube_video_id" ] = debugGoogleYouTubeVideoID
316+ }
317+ return callGoogleAdsTool ("upload_google_ads_asset" , toolArgs )
318+ }
319+
320+ func runDebugGoogleAdsPmaxAssetGroups (cmd * cobra.Command , args []string ) error {
321+ toolArgs := map [string ]interface {}{
322+ "customer_id" : debugGoogleCustomerID ,
323+ "campaign_id" : debugGoogleCampaignID ,
324+ }
325+ return callGoogleAdsTool ("get_google_ads_pmax_asset_groups" , toolArgs )
326+ }
327+
328+ func runDebugGoogleAdsToolsList (cmd * cobra.Command , args []string ) error {
329+ c , err := newGoogleAdsMCPClient ()
330+ if err != nil {
331+ return err
332+ }
333+ result , err := c .ListTools (googleAdsMCPServer )
334+ if err != nil {
335+ return fmt .Errorf ("listing tools: %w" , err )
336+ }
337+ fmt .Fprintf (os .Stderr , "Found %d tools\n \n " , len (result .Tools ))
338+ for _ , tool := range result .Tools {
339+ fmt .Printf ("%-45s %s\n " , tool .Name , truncate (tool .Description , 80 ))
340+ }
341+ return nil
342+ }
343+
344+ func runDebugGoogleAdsCall (cmd * cobra.Command , args []string ) error {
345+ var toolArgs map [string ]interface {}
346+ if err := json .Unmarshal ([]byte (debugGoogleToolArgs ), & toolArgs ); err != nil {
347+ return fmt .Errorf ("invalid JSON in --args: %w" , err )
348+ }
349+ return callGoogleAdsTool (debugGoogleToolName , toolArgs )
112350}
113351
114352// --- TikTok Ads debug (placeholder - not yet implemented server-side) ---
0 commit comments