Skip to main content

Using Gateway and Management MCP Together

An AI agent with access to both Zerq MCP surfaces can do things no single surface alone can: configure a new API integration with Management MCP, then immediately test it via Gateway MCP — all in one conversation, with a single audit trail.

This recipe covers three real-world scenarios that combine both surfaces:

  1. Onboard and verify a new partner — configure the client, profile, and collection access, then call the API as that partner to confirm everything works
  2. Investigate and fix a failing endpoint — query logs and metrics, reproduce the failure, update config, verify the fix
  3. Publish a new API endpoint and smoke test it — create a proxy via Management MCP, then call it immediately via Gateway MCP

How the two surfaces work together

SurfaceWhat it doesAuth
Gateway MCP (/mcp)Discover and call published API endpoints as a gateway clientX-Client-ID, X-Profile-ID, Bearer token
Management MCP (/api/v1/mcp)Configure the platform — collections, proxies, clients, profiles, policies, logs, metricsOIDC Bearer token

An AI agent (Cursor, Claude Desktop, etc.) is configured with both MCP servers simultaneously. The agent decides which surface to use based on what the task requires.


Setup — configure both servers in your AI client

Cursor (mcp.json or Cursor MCP settings)

{
"mcpServers": {
"zerq-gateway": {
"url": "https://api.example.com/mcp",
"transport": "streamableHttp",
"headers": {
"Authorization": "Bearer <GATEWAY_TOKEN>",
"X-Client-ID": "<CLIENT_ID>",
"X-Profile-ID": "<PROFILE_ID>"
}
},
"zerq-management": {
"url": "https://api.example.com/api/v1/mcp",
"transport": "streamableHttp",
"headers": {
"Authorization": "Bearer <OIDC_ACCESS_TOKEN>"
}
}
}
}

Claude Desktop (claude_desktop_config.json)

{
"mcpServers": {
"zerq-gateway": {
"type": "streamableHttp",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer <GATEWAY_TOKEN>",
"X-Client-ID": "<CLIENT_ID>",
"X-Profile-ID": "<PROFILE_ID>"
}
},
"zerq-management": {
"type": "streamableHttp",
"url": "https://api.example.com/api/v1/mcp",
"headers": {
"Authorization": "Bearer <OIDC_ACCESS_TOKEN>"
}
}
}
}
caution

Use separate credentials for each surface. Gateway MCP uses a client/profile token. Management MCP uses an OIDC token from your identity provider. Never mix them.


Scenario 1 — Onboard and verify a new partner

Prompt to AI agent:

"Onboard a new partner called Stripe Payments Ltd. They need read-only access to the invoices-api collection. Rate limit them to 500 requests per minute. Once configured, test that they can call GET /invoices/INV-001."

What the agent does — step by step:

Step 1 — Check existing collections (Management MCP)

// tools/call → list_collections
{
"name": "list_collections",
"arguments": {}
}
// Confirms "invoices-api" exists and is published

Step 2 — Create a rate limit policy (Management MCP)

// tools/call → create_policy
{
"name": "create_policy",
"arguments": {
"name": "partner-standard-500rpm",
"rateLimit": 500,
"rateLimitWindow": "minute",
"dailyQuota": 500000
}
}
// Returns: { "id": "pol-abc123", "name": "partner-standard-500rpm" }

Step 3 — Create the partner client (Management MCP)

// tools/call → create_client
{
"name": "create_client",
"arguments": {
"name": "stripe-payments-ltd",
"email": "[email protected]",
"description": "Stripe Payments Ltd integration",
"collections": ["<invoices-api-collection-id>"],
"policyId": "pol-abc123"
}
}
// Returns: { "id": "cli-xyz789", "clientId": "stripe-payments-ltd" }

Step 4 — Create a read-only profile (Management MCP)

// tools/call → create_profile
{
"name": "create_profile",
"arguments": {
"clientId": "cli-xyz789",
"name": "stripe-read-only",
"authType": "token",
"allowedMethods": ["GET"],
"policyId": "pol-abc123"
}
}
// Returns: { "id": "prf-001", "token": "eyJ..." }

Step 5 — Verify the endpoint exists (Gateway MCP)

The agent now switches to the Gateway MCP surface to confirm the endpoint is discoverable under the agent's own client:

// tools/call → list_endpoints (Gateway MCP)
{
"name": "list_endpoints",
"arguments": { "collectionId": "<invoices-api-collection-id>" }
}
// Confirms GET /invoices/{invoiceId} is present

Step 6 — Execute a test call as the new partner (Gateway MCP)

// tools/call → execute_endpoint (Gateway MCP)
{
"name": "execute_endpoint",
"arguments": {
"endpoint_id": "<get-invoice-endpoint-id>",
"path_params": { "invoiceId": "INV-001" },
"headers": {
"X-Client-ID": "stripe-payments-ltd",
"Authorization": "Bearer eyJ..."
}
}
}
// Returns: { "status": 200, "body": { "id": "INV-001", ... }, "latency_ms": 42 }

Agent response to operator:

"Done. Stripe Payments Ltd (stripe-payments-ltd) is configured with read-only access to invoices-api, rate-limited at 500 req/min. Test call to GET /invoices/INV-001 returned 200 in 42ms. Credentials have been set. Share the Client ID stripe-payments-ltd and Bearer token with the partner."


Scenario 2 — Investigate and fix a failing endpoint

Prompt to AI agent:

"Partner logistics-co is getting 403 errors on GET /shipments. Can you figure out what's wrong and fix it?"

Step 1 — Pull recent error logs (Management MCP)

// tools/call → list_logs
{
"name": "list_logs",
"arguments": {
"clientId": "logistics-co",
"status": 403,
"limit": 10
}
}
// Returns 10 recent 403 logs for this client — all hitting GET /shipments

Step 2 — Check the client profile (Management MCP)

// tools/call → get_client
{
"name": "get_client",
"arguments": { "clientId": "logistics-co" }
}
// Returns: client record with profile IDs

// tools/call → get_profile
{
"name": "get_profile",
"arguments": { "profileId": "prf-logistics-001" }
}
// Returns: { "allowedMethods": ["POST"], "authType": "token" }
// ← Problem found: GET is not in the allowed methods list

Step 3 — Reproduce the error via Gateway MCP (optional)

// tools/call → execute_endpoint (Gateway MCP)
{
"name": "execute_endpoint",
"arguments": {
"endpoint_id": "<shipments-get-endpoint-id>",
"headers": {
"X-Client-ID": "logistics-co",
"Authorization": "Bearer <logistics-token>"
}
}
}
// Returns: { "status": 403, "body": { "error": "method_not_allowed" } }
// Confirms the issue

Step 4 — Fix the profile (Management MCP)

// tools/call → update_profile
{
"name": "update_profile",
"arguments": {
"profileId": "prf-logistics-001",
"allowedMethods": ["GET", "POST"]
}
}
// Returns: { "status": "updated" }

Step 5 — Verify the fix (Gateway MCP)

// tools/call → execute_endpoint (Gateway MCP)
{
"name": "execute_endpoint",
"arguments": {
"endpoint_id": "<shipments-get-endpoint-id>",
"headers": {
"X-Client-ID": "logistics-co",
"Authorization": "Bearer <logistics-token>"
}
}
}
// Returns: { "status": 200, "body": { "shipments": [...] }, "latency_ms": 55 }

Agent response to operator:

"Found it. The profile prf-logistics-001 for client logistics-co only allowed POSTGET was missing. I've added GET to the allowed methods. Re-tested GET /shipments and it now returns 200 in 55ms. The last 10 error logs were all the same root cause."


Scenario 3 — Publish a new proxy and smoke test it

Prompt to AI agent:

"Add a new GET /orders/{orderId}/status endpoint to the orders-api collection pointing to https://order-status.internal/v2/status/{orderId}. Then test that it works."

Step 1 — Get the collection ID (Management MCP)

// tools/call → list_collections
{
"name": "list_collections",
"arguments": {}
}
// Returns list — agent finds: { "id": "col-orders-001", "name": "orders-api" }

Step 2 — Create the proxy (Management MCP)

// tools/call → create_proxy
{
"name": "create_proxy",
"arguments": {
"collectionId": "col-orders-001",
"name": "Get Order Status",
"method": "GET",
"path": "/orders/{orderId}/status",
"targetPath": "/v2/status/{orderId}",
"description": "Returns the current fulfillment status for an order"
}
}
// Returns: { "id": "prx-status-001", "path": "/orders/{orderId}/status" }

Step 3 — Validate and publish (Management MCP)

// tools/call → validate_proxy_workflow
{
"name": "validate_proxy_workflow",
"arguments": { "proxyId": "prx-status-001" }
}
// Returns: { "valid": true }

// tools/call → toggle_collection_status
{
"name": "toggle_collection_status",
"arguments": { "collectionId": "col-orders-001", "active": true }
}
// Returns: { "status": "active" }

Step 4 — Discover the new endpoint (Gateway MCP)

// tools/call → list_endpoints (Gateway MCP)
{
"name": "list_endpoints",
"arguments": { "collectionId": "col-orders-001" }
}
// New endpoint "Get Order Status" appears in the list — endpoint_id: "ep-status-001"

Step 5 — Execute a test call (Gateway MCP)

// tools/call → execute_endpoint (Gateway MCP)
{
"name": "execute_endpoint",
"arguments": {
"endpoint_id": "ep-status-001",
"path_params": { "orderId": "ORD-7890" }
}
}
// Returns: { "status": 200, "body": { "orderId": "ORD-7890", "status": "shipped", ... }, "latency_ms": 38 }

Agent response to operator:

"Done. GET /orders/{orderId}/status is live in orders-api, routing to https://order-status.internal/v2/status/{orderId}. Test call for order ORD-7890 returned 200 in 38ms with status shipped. The proxy is published and visible in Gateway MCP."


Tool reference summary

TaskSurfaceTool
List what APIs existManagement or Gatewaylist_collections
Create a collectionManagementcreate_collection
Add a proxy/endpointManagementcreate_proxy
Publish a collectionManagementtoggle_collection_status
Create a clientManagementcreate_client
Create a profileManagementcreate_profile
Fix profile methodsManagementupdate_profile
Check error logsManagementlist_logs
Query metricsManagementget_metrics_overview
Discover callable endpointsGatewaylist_endpoints
Get endpoint schema/paramsGatewayendpoint_details
Execute an API callGatewayexecute_endpoint

Audit trail

Every tool call from both surfaces is recorded in the platform audit log. Open Logs → Audit Logs and you will see Management MCP configuration changes and Gateway MCP execute calls side by side — actor, timestamp, and action — regardless of whether they came from the UI or an AI agent.


Next steps