Repository navigation
1.9.79: update and delete tools for traffic sources, their accounts and categories in the MCP connector - #280
Conversation
…categories ppc_network_update/_delete, ppc_account_update/_delete and aff_network_update/_delete run p202 ppc-network, ppc-account and aff-network update and delete, which already existed. The connector could only list and create these, so a rename made a second source and an account's default flag could not be changed. A delete removes the one record (soft delete), as Setup › Traffic Sources and Setup › Categories do; the delete tools' descriptions say that a source's accounts and a category's campaigns stay, and name the tool that removes them. The hosted connector needs no new scope: AiConnect's WRITE_AREAS already covers ppc-networks, ppc-accounts and aff-networks. The catalogue budget goes to 85,000 characters for the six tools (about 4,600). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…category Search tasks for ppc-network, ppc-account and aff-network update, with the words a rename is asked in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ecords SetupObjectsWriteScopeIntegrationTest: an update renames the record in place (same id, no new row, children still name it); another account's source, account or category answers 404 for an update, a delete and a dry run and is left as it was; a delete soft-deletes that one row, leaves the source's accounts and the category's campaigns, and its dry run reports mode soft with an empty cascade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setup-source-001 asks for "EVAL Source - Main" to be renamed and checks one source under the new name, none under the old, and its account still under it; creating or deleting a source or account fails it. The reference agent runs p202 ppc-network update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MCP section names the new tools; cli.md, cli-agent.md and the OpenAPI DELETE descriptions say a delete removes the source, account or category alone and what stays. Changelog entry for both changelogs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: da4d5dfce2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| {Name: "ppc_network_delete", Command: []string{"ppc-network", "delete"}, Title: "Delete a traffic source", Kind: mcpDelete, Args: []mcpArg{idArg("id", "Traffic source id (from ppc_network_list); or give ids for several.", false)}, Note: setupParentDeleteNote("traffic source", "accounts", "ppc_account_delete")}, | ||
| {Name: "ppc_account_list", Command: []string{"ppc-account", "list"}, Title: "List traffic source accounts", Kind: mcpRead, HostedOmit: mcpEveryPage}, | ||
| {Name: "ppc_account_create", Command: []string{"ppc-account", "create"}, Title: "Create a traffic source account", Kind: mcpCreate}, | ||
| {Name: "ppc_account_update", Command: []string{"ppc-account", "update"}, Title: "Update a traffic source account", Kind: mcpUpdate, Args: []mcpArg{idArg("id", "Traffic source account id (from ppc_account_list).", true)}}, |
There was a problem hiding this comment.
Restrict
none to report filters
The new ppc_account_update tool inherits mcpIDFlagPattern for its ppc_network_id flag, whose schema accepts none even though that exception is intended only for report filters. Thus an MCP client can submit a schema-valid request such as {"id":"9","ppc_network_id":"none"}, but the PPC account controller requires an integer and rejects the update with a 422. Generate the numeric-only pattern for this update field, or make the none exception depend on the command being a report.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 62d30b1: mcpIDFlagPattern now takes the tool kind and offers none for ppc_network_id only on read tools (the report filters). On write tools (ppc_account_create, ppc_account_update) the field is digits only, and {"ppc_network_id":"none"} is refused before any request. TestMCPToolArgv pins it: none is refused on ppc_account_update and ppc_account_create, and report_summary still takes none. The two refusal cases fail against the previous mcp_catalog.go. go test ./cmd/ passes.
mcpIDFlagPattern gave every ppc_network_id the report filters' pattern, digits or none, so ppc_account_create and ppc_account_update advertised and sent none, which the API refuses. none is now a read tool's only; the argv tests pin none refused on both writes and still taken by report_summary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#280's traffic source and category update and delete tools sit beside the text ad writes in the catalogue; text_ad_list takes #279's hosted omission of all. The catalogue budget goes to 88,000 characters: #280's tools and the text ad writes together come to about 87,800. The docs keep #281's hosted read bounds, then the text ad reconnect note; the changelogs keep 1.9.79's lines and put the text ad lines after them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr
…start IPN branch
GET /users/{id}/preferences now serves every integration secret as its
stored state (#270), and the PayKickstart IPN keys are one more:
paykickstart_ipn_secret_keys is on ServedPreferences::SECRET, answered
{"stored": true}, and the count this branch served in its place
(paykickstart_ipn_keys_stored, PayKickstartKeys::withoutKeys()) is gone.
GET /system/integrations keys_stored still says how many. The
PreferenceSecretsAreNotServedIntegrationTest round trip stores the keys
with the other secrets.
Conflicts: changelogs (1.9.79's lines, then this branch's), the
preferences docs and the OpenAPI schemas (1.9.79's, with the keys added
as a StoredSecret), and the controller (1.9.79's).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr
The catalogue keeps #280's traffic source, account and category updates and deletes beside the rotator writes, and rotator_list takes #279's hosted omission of --all. Both changelogs keep the version branch's lines and add this branch's. The tool list is 89,469 characters with both; its budget is 90,000. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr
"set the api url" ranked p202 system integrations level with config set-url once the rotator writes and #280's tasks were both in the index: the two had scored within half a percent on the version branch, and the new commands' words moved the weights enough to tie them. config set-url now has a search task with the words the docs use for what it sets, the install's base URL or instance URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr
…JVZoo branch #268 now dates a notification's row by the provider's own time, held to the click for a sale and to the sale for a refund, and brings 1.9.79's #270 (ServedPreferences: GET preferences serves each secret as {"stored": ...}), #280, #281 and #282. Conflicts: both changelogs keep the base's lines with the JVZoo line after them; the OpenAPI preferences update takes #270's oneOf shape, with the JVZoo key's rule in its string branch; the eval cases keep #268's admin-005 notes and add admin-006 after it. jvzoo_ipn_secret_key is already on ServedPreferences::SECRET, and JVZoo adds no other column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr
…79's #270, #280, #281, #282) into the ClickBank branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr # Conflicts: # 202-config/changelogs.json # changelogs.txt
Backlog item mcp-setup-objects-crud.
The MCP connector (
p202 mcpand the hosted server) could only list and create traffic sources (ppc_network), traffic source accounts (ppc_account) and categories (aff_network). So when asked to rename "Google Ads - Main" to "Main" it could only make a second source, and an account's default flag could not be changed after it was created. This PR adds:ppc_network_update,ppc_network_deleteppc_account_update,ppc_account_deleteaff_network_update,aff_network_deleteThese are the same kind of tool as
landing_page_update/_delete. Each runs thep202 <entity> update|deletecommand, and those commands, likePUT/DELETE /api/v3/{ppc-networks,ppc-accounts,aff-networks}/{id}, already existed. So nothing changes in the API or in the CLI commands.What happens on a delete
*_deletedflag), run through the tool with--forceonce the call is approved, anddry_run: truegives a preview first (deleteNote).ppc_accounts.php,aff_networks.phpset the flag on that one row) and the API'sController::deleteRecord(). A campaign delete likewise leaves its trackers. A deleted source's accounts and a deleted category's campaigns stay and still name their parent. The dry run'scascadeis[]. I did not add a cascade or a refusal, because either would make the API disagree with the Setup pages. Instead, the delete tools' descriptions say what stays and name the tool that removes it (ppc_account_delete,campaign_delete). The OpenAPI DELETE descriptions and the CLI docs say the same.Account scoping (IDOR)
get()/update()/deleteRecord()filter onuser_id, andassertLinksOwnedchecksppc_network_idon an account update.tests/Api/V3/SetupObjectsWriteScopeIntegrationTest:AiConnect::WRITE_AREASalready holdsppc-networks,ppc-accountsandaff-networks. Existing connections need no reconnect, and neitherAiConnect.phpnorconnect-ai.phpchanges. Its copy already says "change and delete ... traffic sources and categories".Also in this PR
p202 searchtasks for the threeupdatecommands.setup-source-001: rename in place, no create or delete. Reference agent branch included.documentation/cli/10-go-cli.md,docs/cli.md,docs/cli-agent.md,docs/openapi.yaml.changelogs.txtand202-config/changelogs.json.Overlap with #260, #265, #267
landing_page_update;*[Dd]elete*).TestMCPCatalogStaysInBudget'sbudget. This PR sets it to 85000 and 1.9.79: text_ad_create, text_ad_update and text_ad_delete in the MCP connector #260 to 84000. Whichever merges second should add the two increases together (about 4,600 here and 3,400 there).crud.go,AiConnect.php,connect-ai.php, the legacy Setup pages andapi/v1/functions.phpare not touched.Verification (local, macOS, PHP 8.5, MySQL 8.0 in Docker)
cd go-cli && go vet ./cmd/ && go test ./cmd/passed. TheTestMCPToolArgvcases are new. The hosted-scope test runs every tool in each mode against AiConnect's areas.SetupObjectsWriteScopeIntegrationTest: 3 tests, 84 assertions, OK. It is not vacuous: with theuser_idscope removed fromPpcNetworksController, the cross-account test fails.OwnedReferencesIntegrationTest,PayloadValidationIntegrationTestandIntegrationSuiteSelectionTestpassed.verify.sh --changed --since origin/1.9.79:phpstan-strictfindings are inConnection.phpandLookupRepositoryFactory.php, which this PR does not touch. The unit tier's failures are the same 14 test files with identical counts onorigin/1.9.79(checked with these changes stashed), so they come from PHP 8.5, not from this change.setup-source-001.