This guide covers operating PAG day to day, once you're connected (if you're not yet, start at the README). It goes deeper than the getting-started page on each topic.
- Managing servers --- add, enable, disable, restart, configure, and control which tools are exposed
- The dashboard --- PAG's browser UI
- Catalog and registries --- discover and install servers
- Perforce servers --- the first-party servers
- Tools and the sandbox --- how your assistant reaches downstream tools, in full
Everything you can do to a server --- add, enable, disable, restart, configure --- is available three ways:
- Conversationally, by asking your AI assistant (PAG's management tools)
- Visually, in the dashboard (
uvx perforce-agentic-gateway view) - Directly, by editing config files (see the configuration reference)
All three write to the same configuration. PAG watches its config files, so changes apply live --- running servers are started, stopped, or reconfigured without restarting PAG or your AI client.
A server entry is one of four kinds, depending on which fields it sets:
| Kind | Key fields | PAG runs it as |
|---|---|---|
| Registry-sourced | source (e.g. "com.perforce/p4") |
Whatever the registry entry specifies |
| Local command | command, args |
A subprocess speaking MCP over stdio |
| Container | image, volumes |
A container via your configured runtime |
| Remote HTTP | url, headers, transport |
A connection to a remote MCP endpoint (streamable-http by default, or sse) |
Every server has an alias --- the short name you choose for it (e.g. p4, blazemeter). Aliases may contain letters, digits, dashes, and underscores, but not double underscores (__), which PAG reserves as its namespacing separator. The names pag and ui_builder are reserved for PAG's own use.
Conversationally --- ask your assistant to find and enable servers:
"What MCP servers would help with this project?" --- runs
pag__discover, which scans your project for technology signals and recommends catalog servers. It always asks before enabling.
"Search the catalog for BlazeMeter and enable it." --- runs
pag__search_catalogthenpag__enable_server.
"Add a custom server called mytool that runs
npx -y @example/mcp-server." --- runspag__add_server.
If the server requires secrets, the assistant replies with a dashboard link where you enter them --- secrets never travel through the chat. See Secrets.
Dashboard --- the Catalog page lists everything from your configured registries; the Add page covers custom servers. See Catalog and registries.
Config file --- add a [servers.<alias>] block:
[servers.p4]
source = "com.perforce/p4"
enabled = true
[servers.mytool]
command = "npx"
args = ["-y", "@example/mcp-server"]
enabled = true
[servers.internal-api]
url = "https://mcp.example.internal/v1"
enabled = trueA disabled server stays in your configuration but is not started, and its tools disappear from the catalog your assistant sees.
- Ask: "Disable p4 for now" / "Enable p4 again"
- Dashboard: toggle on the server's page
- Config:
enabled = true/enabled = falseon the server block
If a server gets into a bad state:
- Ask: "Restart the p4 server" (
pag__restart_server) - Dashboard: restart button on the server's page
- Ask: "What's the status of my servers?" (
pag__status) --- reports each server's state:starting,running,stopped, ordisabled, plus available updates. - Ask: "Show me recent logs from p4" (
pag__server_logs) --- returns the server process's recent stderr output. - Dashboard: health is shown per server, and the Activity tab shows the server's health history and recent logs.
Registry servers declare inputs --- settings such as paths, URLs, project names, and secrets. Update them any time:
- Ask: "Change p4's project path to /src/myapp" (
pag__configure_server) - Dashboard: the server's Config tab
- Config file: the server's
env,args,[inputs.*], and[remote.variables]sections --- see the configuration reference
You can trim a server's tool list --- useful for keeping the catalog focused or blocking tools you don't want used. Each downstream tool is either enabled (visible in the catalog and callable) or disabled (blocked entirely).
[servers.p4.tools]
default = "enabled" # or "disabled"
disabled = ["delete_project", "admin_config"]With default = "disabled" you can flip to an allow-list:
[servers.p4.tools]
default = "disabled"
enabled = ["get_issues", "list_projects"]The dashboard's Tools tab shows the same switches visually. A tool may not appear in both lists.
Servers defined in your global config (~/.config/pag/config.toml) are available in every project. Servers in a project's .pag/config.toml apply to that project and can be committed to share with your team. Machine-specific tweaks go in .pag/config.local.toml, which overrides the project layer and is meant to stay out of version control. Later layers override earlier ones per server alias.
The dashboard is PAG's browser UI for managing servers, browsing the catalog, and entering secrets.
From your project directory:
uvx perforce-agentic-gateway viewPAG starts, prints the dashboard URL, and opens it in your default browser. The dashboard serves on 127.0.0.1 (localhost) only --- it is never reachable from other machines.
Each project gets a stable port, derived from the project's identity (its version-control remote URL, falling back to its path), in the range 49152--65535. Bookmarks keep working across restarts. If the derived port happens to be in use, PAG falls back to a random free port --- the printed URL is always authoritative.
The dashboard is also available while PAG is running inside an AI client session --- when your assistant needs you to enter secrets, it hands you a link into the same UI.
The home page lists your configured servers with their health state:
| State | Meaning |
|---|---|
starting |
PAG is launching/connecting the server |
running |
Healthy and serving |
stopped |
Exited or unreachable |
disabled |
Configured but turned off |
An update available badge appears when a registry server has a newer version than the one you're pinned to.
Each server has a detail page with three tabs:
- Activity --- the server's health-state history and its recent log output
- Config --- its settings: inputs, environment variables, arguments; edit and save here. Missing secrets are flagged, with a link to the secret entry page
- Tools --- every tool the server exposes, with per-tool enable/disable switches (see Controlling which tools are exposed)
Secret entry is its own page (linked from the Config tab and from the links your assistant hands you), where you can enter or replace each secret the server requires.
Plus actions: enable/disable, restart, and remove.
Searchable listing of every server available from your configured registries. Pick a server, fill in its inputs and secrets, choose an alias, and add it to your project or global configuration. A refresh action re-fetches the registries. See Catalog and registries.
A read-only list of your active registries (the Perforce default plus any you've added), each showing its health --- reachable, serving cached results, failed, or not yet checked --- and a refresh action. You add or remove registries by editing config, not here.
A form for custom servers that aren't in any registry --- local commands, containers, or remote HTTP endpoints.
- Binds to
127.0.0.1only; never exposed to the network. - Browser-level protections (origin checks, CSRF protection, a strict content-security policy) prevent other websites from scripting against it.
- There is no login: anyone with local access to your machine session can open it, same as your terminal.
Secrets entered in the dashboard go straight into your OS keychain (or PAG's fallback secret store) --- see Secrets.
A registry is an HTTP catalog of installable MCP servers. PAG fetches server listings from your configured registries, caches them locally, and merges them into the catalog --- the set of servers you can browse in the dashboard, search conversationally, and enable with one step.
Out of the box, your catalog is populated from the Perforce registry --- no setup needed to get the first-party Perforce servers (see Perforce servers) and other published MCP servers. To pull from additional registries, add [[registries]] blocks (see Adding registries).
- Dashboard: the Catalog page lists everything, with search.
- Conversationally: "Search the catalog for performance testing" runs
pag__search_catalog. With no query it lists all available servers. - Project-aware: "What servers would help with this project?" runs
pag__discover, which combines a scan of your project's technology signals with catalog searches and presents recommended servers for your approval.
When you pick a catalog server (in the dashboard, or by asking your assistant to enable it), PAG:
- records it in your config under the alias you choose, with
sourceset to the server's registry name (e.g.com.perforce/p4); - prompts for any inputs the server declares --- paths, project names, options;
- prompts for any secrets --- these go to the dashboard's secret entry, never through chat (see Secrets);
- starts it and exposes its tools in the catalog your assistant queries.
In config form, an installed catalog server is compact --- the registry supplies the run details:
[servers.p4]
source = "com.perforce/p4"
enabled = true
# Inputs the server declares, if any --- for example:
[servers.p4.inputs.PROJECT_ROOT]
value = "/src/myapp"You can pin a version with version = "..."; otherwise PAG shows an update available badge in the dashboard when the registry has something newer.
If two registries offer the same server name, disambiguate with registry = "<registry url>" on the server block.
Add entries to your global or project config:
[[registries]]
url = "https://registry.example.com/mcp/v1"Registries are fetched in order and merged. Entries must be http:// or https:// URLs.
For air-gapped setups or testing, a registry can be a local directory:
[[registries]]
url = "file:///absolute/path/to/catalog"
type = "devcatalog"Registry listings are cached on disk (in PAG's data directory) so startup doesn't depend on the network. The dashboard's Catalog page has a refresh action that re-fetches all registries.
Perforce publishes first-party MCP servers for its products through the default registry, so they appear in your catalog by default. First-party servers include:
| Server | What it gives your assistant |
|---|---|
P4 (com.perforce/p4) |
Perforce P4 version control --- manage files, changelists, shelves, workspaces, jobs, and reviews |
BlazeMeter (com.perforce/blazemeter) |
Cloud-based performance testing --- load-testing workflows from creation to execution and reporting |
BlazeMeter API Monitoring (com.perforce/blazemeter-apitest) |
API monitoring --- teams, buckets, tests, schedules, environments, and results |
BlazeMeter Service Virtualization (com.perforce/blazemeter-sv) |
Create, configure, and manage virtual services |
Perfecto (com.perforce/perfecto) |
Cloud-based web and mobile testing --- workflows from creation to execution |
Delphix DCT (com.perforce/delphix-dct) |
Delphix Data Control Tower --- self-service data provisioning and management |
IPLM (com.perforce/iplm) |
Perforce IPLM (IP Lifecycle Management) --- IPs, libraries, releases, and design data |
IPLM Docs (com.perforce/iplm-docs) |
Searchable access to Perforce IPLM product documentation |
The catalog is the authoritative, up-to-date list --- the registry gains servers over time without you updating PAG.
Same as any catalog server (see Adding a server):
- Ask your assistant: "Enable the P4 server" --- or run "What servers would help with this project?" and PAG's discovery will recommend the relevant Perforce servers based on the technology signals in your project.
- Or use the dashboard's Catalog page.
Each server prompts for the connection settings and credentials it needs (for example, your server URL and an access token). Credentials are entered through the dashboard and stored in your OS keychain --- see Secrets.
This section explains what your assistant sees when it connects to PAG and how it reaches your downstream servers' tools. (For the short version, see Why it stays fast in the README.)
PAG does not forward every downstream tool definition to your AI client. A setup with 20 servers might expose a thousand tools --- flooding the assistant's context window before the conversation even starts.
Instead, PAG presents a fixed set of eleven pag__* tools:
| Tool | Purpose |
|---|---|
pag__explore |
Search the tool catalog with JavaScript --- find tools, read their schemas |
pag__execute |
Run JavaScript that calls downstream tools and returns structured results |
pag__discover |
Scan the project for technology signals and recommend servers to enable |
pag__search_catalog |
Search the configured registries for installable servers |
pag__enable_server |
Enable a registry server for this project |
pag__add_server |
Add a custom server (command, container, or URL) |
pag__disable_server |
Disable a server |
pag__restart_server |
Restart a server |
pag__configure_server |
Update a server's inputs, environment, or arguments |
pag__status |
Report server health states |
pag__server_logs |
Retrieve a server's recent stderr output |
Downstream tools are reached through pag__execute, and discovered through pag__explore. The full catalog of downstream tools lives inside PAG --- it enters the assistant's context only in the filtered slices the assistant asks for.
Every downstream tool gets a qualified name: <alias>__<toolname> --- the server alias you chose, a double underscore, and the tool's own name. For example, a get_issues tool on the server you aliased klocwork is klocwork__get_issues. (This is why aliases may not contain __.)
Resources from downstream servers are addressed as <alias>+<original uri>. Prompts follow the same __ convention as tools.
A typical request flows in two steps:
1. Explore. The assistant queries the catalog with a small JavaScript program against a catalog object:
// Find tools related to "issues" and inspect their schemas
const allTools = Object.entries(catalog).flatMap(
([alias, {tools}]) => tools
);
const hits = fuzzy("issues", allTools, "name");
return hits.map(h => ({
qualifiedName: h.item.qualifiedName,
description: h.item.description,
inputSchema: h.item.inputSchema
}));pag__explore is read-only: it can search and inspect, never call. A built-in fuzzy() helper does approximate matching so typos and partial terms still find the right tools.
2. Execute. The assistant writes a program that calls the tools it found:
// One round trip: fetch two things in parallel, combine them.
// Promise.allSettled keeps one failure from sinking the batch; each
// thrown error already names the failed tool --- its .message is
// prefixed "<server__tool>: <reason>" --- so surface it whole.
const names = ["klocwork__get_issues", "klocwork__get_metrics"];
const settled = await Promise.allSettled(
names.map(name => callTool(name, { project: "myapp" }))
);
return settled.map(r =>
r.status === "fulfilled"
? { data: JSON.parse(r.value[0].text) }
: { error: r.reason.message } // e.g. "klocwork__get_metrics: ..."
);Because the program runs inside PAG, multi-step workflows --- loops, conditionals, fan-out across servers, error handling per server --- happen in one tool call instead of many model round trips, and intermediate results never bloat the conversation.
pag__execute and pag__explore programs run in a locked-down JavaScript sandbox inside the PAG process:
- Plain JavaScript with
async/await. No TypeScript, no imports. - A fresh sandbox per call --- no state persists between calls.
- No ambient capabilities: no
fetch, norequire, noprocess, no timers, noeval. The only way a program can affect the outside world iscallTool()--- and inpag__explore, not even that. - Execution timeout: a runaway program is stopped after 120 seconds.
console.log()output is captured and returned alongside the result, which helps the assistant debug its own programs.
callTool() reaches only tools that are enabled --- servers you have enabled, minus any tools you switched off (see Controlling which tools are exposed). Disabled tools are absent from the catalog and blocked from calling.
Beyond tools, PAG also aggregates downstream servers' prompts and resources and serves them to your client through the standard MCP methods (listing, reading, resource subscriptions, and argument completions), using the qualified-name conventions above. If a client asks for a resource by its bare original URI, PAG resolves it to the right server when the URI is unambiguous.
When a downstream server fails in a way that needs your attention, PAG sends a notification through the MCP connection so your assistant can tell you about it --- for example, a server that exited because a required secret is missing.