> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Scope agent tools with a virtual MCP server

Implement with AI

Send this guide to your coding agent.

Prerequisite: Install Port MCP

This guide shows how to build a virtual MCP server for one job. We will start with a short list of tools, rename them so agents pick the right one, scope them to a single service, and block changes to production.

Common use cases​

  • Give a coding agent only the catalog tools it needs for one service.
  • Let an on-call agent investigate incidents without write access.
  • Let agents run self-service actions on test and staging, but never on production.

Prerequisites​

  • Virtual MCP servers enabled for your organization. This feature is currently in closed beta. Contact Port's support team to request access.
  • MCP connectors for any external tools you want to expose, such as GitHub or Datadog.

Step 1: Expose selected tools as they are​

Start with passthrough patterns only. Pick the tools the job needs and leave them unchanged. Customize a tool later, only when you need to rename it or limit its arguments.

  1. Go to the Virtual MCPs tab of the MCPs page.
  2. Click + Virtual MCP Server.
  3. Turn on JSON Mode.
  4. Paste the following JSON, then click Register:
{
"identifier": "checkout-oncall",
"title": "Checkout on-call",
"properties": {
"description": "Tools for investigating issues in the checkout service.",
"instructions": "You help on-call engineers investigate the checkout service. Read data before suggesting changes.",
"passthrough_tools": ["list_blueprints", "list_entities", "github_list_commits"]
}
}

The github_ prefix is the identifier of a GitHub MCP connector. Use the connector's identifier, not its title.

Step 2: Rename tools for agents​

Agents choose tools by name and description, so write both for an agent that is picking a tool for a task:

  • Name each tool after the question it answers or the action it performs, as a verb and an object. Start read tools with get or list.
  • Leave vendor names out of tool names.
  • In the description, say when to use the tool, when not to, and whether it only reads data or changes something.
  • Only describe what the underlying tool actually does.
Underlying toolExposed name
list_entitieslist_catalog_records
list_blueprintsdescribe_catalog_record_types
list_self_service_triggerslist_available_actions
trigger_runrun_action
github_list_commitslist_recent_commits
datadog_search_datadog_logslist_error_logs

For each tool you rename, create a virtual tool and add it to the server:

  1. Go to the Virtual Tools tab of the MCPs page.

  2. Click + Virtual Tool.

  3. Turn on JSON Mode.

  4. Paste the virtual tool JSON, then click Register. For example, this virtual tool renames list_blueprints:

    {
    "identifier": "describe_catalog_record_types",
    "title": "Describe catalog record types",
    "properties": {
    "name": "describe_catalog_record_types",
    "tool": "list_blueprints",
    "description": "List the types of records in the catalog and the fields each type has. Read only. Use it before listing records, to learn which fields you can filter on."
    }
    }
  5. Go back to the Virtual MCPs tab and open the checkout-oncall server for editing.

  6. Select the new virtual tool in Virtual Tools.

  7. Remove the underlying tool from Passthrough Tools, so the agent does not see both versions, then click Update.

The following steps reuse this procedure for every virtual tool you create.

Step 3: Scope tools to a service and its blast radius​

To keep an agent on one service and the entities connected to it, fix a relatedTo filter on list_entities. With merge: append, the agent can still add its own filters, but the service filter is always applied.

Create the following virtual tool and add it to the server, as described in step 2. It replaces a generic rename of list_entities, so if you already created list_catalog_records, remove it from the server:

{
"identifier": "list_checkout_records",
"title": "List checkout records",
"properties": {
"name": "list_checkout_records",
"tool": "list_entities",
"description": "List catalog records related to the checkout service, such as its dependencies and the services that depend on it. Read only.",
"arguments": {
"query.combinator": { "value": "and" },
"query.rules": {
"value": [
{
"combinator": "or",
"rules": [
{ "operator": "relatedTo", "blueprint": "service", "value": "checkout", "direction": "upstream" },
{ "operator": "relatedTo", "blueprint": "service", "value": "checkout", "direction": "downstream" }
]
}
],
"merge": "append"
}
}
}
}

Fixing query.combinator to and matters: with or, the agent's own rules could widen the results past the service filter.

Use the service's identifier, not its title. For more on direction, see relation operators.

Step 4: Block changes to production​

Write tools need stricter rules than read tools. Fix every argument that decides what the tool changes.

Self-service actions. On trigger_run, fix the action with identifier and the trigger node with nodeIdentifier. The inputs argument is a free-form object argument, so you cannot fix one key inside it. Instead, create one virtual tool per allowed action and environment, and set the whole inputs object with value.

Create the following virtual tool and add it to the server, as described in step 2:

{
"identifier": "restart_checkout_staging",
"title": "Restart checkout in staging",
"properties": {
"name": "restart_checkout_staging",
"tool": "trigger_run",
"description": "Restart the checkout service in staging. Changes the running service. Never affects production.",
"arguments": {
"identifier": { "value": "restart_service" },
"nodeIdentifier": { "value": "trigger" },
"inputs": { "value": { "workload": "checkout-staging" } }
}
}
}

Catalog updates. An enum on the entity identifier is not enough on upsert_entity, since the identifier is optional and the agent can omit it. Create one virtual tool per record the agent may update, and fix both blueprintIdentifier and entity.identifier with value. The agent can still edit that record's properties and relations.

MCP connector tools. Apply the same rules to external write tools. For example, add an enum that only allows test and staging clusters, and fix any flag that should never change. Read the real values from your catalog or a read-only tool first. Never guess them.

When the scoped tools are in place, edit the checkout-oncall server:

  1. Remove the generic trigger_run and upsert_entity from Passthrough Tools.
  2. Update Instructions to match what the agent can now do.
  3. Click Update.

Step 5: Connect and test​

Copy the server's URL from its URL property, then connect the server to your IDE or to a Port AI agent, as described in connect a virtual MCP server.

Test the server​

Send the agent the following prompts and compare its behavior with the expected result:

PromptExpected result
"What tools do you have?"Only the tools you exposed, under their new names. No list_entities, trigger_run, or upsert_entity.
"List the dependencies of the checkout service."The agent calls list_checkout_records and returns only records related to checkout.
"List all services in the catalog."The results still only include checkout and the services related to it.
"Restart checkout in staging."The agent calls restart_checkout_staging.
"Restart checkout in production."The agent declines, because it has no tool that can change production.

If the agent can still call a generic tool, check that no pattern in Passthrough Tools matches it.