Skip to content
Scalekit Docs
Talk to an Engineer Dashboard

Create a Virtual MCP server

Create an AgentKit Virtual MCP server with only the tools an agent needs, then list, update or delete it, with examples in Python, Node.js and cURL.

Create one Virtual MCP server for each agent role. It lists the connections and tools the agent can use, and gives you a fixed URL that every user of that agent shares. You do this once, not once per user.

  • A connection for each app the agent needs, in AgentKit > Connections. Set up a connection if you haven’t. These examples use github-connect, the GitHub connection new environments include.

  • A client set up as in the Quickstart: actions in Python, scalekit in Node.js. For cURL, get an access token and keep it in TOKEN:

    Terminal window
    TOKEN=$(curl -sS "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \
    -d grant_type=client_credentials \
    -d client_id="$SCALEKIT_CLIENT_ID" \
    -d client_secret="$SCALEKIT_CLIENT_SECRET" | jq -r .access_token)
  1. Pick the smallest set of tools the agent needs. Get exact names from tool search or the scoped tool list, or from each connector’s page in the connector catalog.

    If you leave out tools for a connection, the server gets every tool that connection has when you create it. Tools added to the connector later aren’t included.

  2. Give the server a name that’s unique in the environment, and list the tools for each connection.

    from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping
    response = actions.mcp.create_config(
    name="repo-assistant",
    description="Reads the user's GitHub repositories and issues",
    connection_tool_mappings=[
    McpConfigConnectionToolMapping(
    connection_name="github-connect",
    tools=["github_user_repos_list", "github_issues_list"],
    ),
    ],
    )
    config_id = response.config.id
    mcp_server_url = response.config.mcp_server_url
    print(config_id, mcp_server_url)
  3. Store the server’s id and mcp_server_url in your configuration. You pass the ID when you mint session tokens, and the URL to your agent. For cURL, keep them in CONFIG_ID and MCP_SERVER_URL.

List servers by name to see the new server and its URL:

response = actions.mcp.list_configs(filter_name="repo-assistant")
for config in response.configs:
print(config.id, config.name, config.mcp_server_url)

Then mint a session token and list the server’s tools from an MCP client.

A server exposes its tools in one of two modes, set with tool_exposure:

  • DIRECT: the agent sees every tool you map to the server. A server can map up to 25 connections, and two connections can’t map tools with the same name.
  • META: the agent sees five tools, search_available_tools, list_available_tools, get_tool_details, execute_tool and connect_account, and uses them to find and run the tools you mapped. A server can map more than 25 connections, and tool names can repeat across connections.

Choose META when an agent needs more connections or tools than it can list at once. If you leave tool_exposure out, the server uses DIRECT. The response’s tool_exposure shows the server’s mode.

response = actions.mcp.create_config(
name="support-agent",
connection_tool_mappings=[
McpConfigConnectionToolMapping(
connection_name="github-connect",
tools=["github_user_repos_list", "github_issues_list"],
),
],
tool_exposure="META",
)

To switch an existing server, pass tool_exposure to the update call. Leave it out to keep the current mode. After a switch, MCP clients must list the server’s tools again; session tokens you already minted keep working. A switch to DIRECT fails while the server maps more than 25 connections or two of its connections map tools with the same name: remove mappings first.

The agent finds a tool, reads its input schema, and runs it as the user:

  1. list_available_tools with no arguments returns each connection on the server with its provider, tool_count and readiness. With a connection_name, it returns that connection’s tools a page at a time.
  2. search_available_tools finds tools by keywords, such as create issue. Each match names its connection_name.
  3. get_tool_details returns one tool’s input_schema. The agent calls it before execute_tool.
  4. execute_tool runs the tool with tool_name, connection_name and input, using the user’s own connected account.

readiness tells the agent whether the user can run a connection’s tools now:

readinessMeaning
readyThe user’s connected account is ACTIVE.
needs_reauthThe user’s connected account is EXPIRED, so the user must authorize the app again.
needs_connectionThe user has no ACTIVE or EXPIRED account for this connection, for example they never finished authorizing it.

If execute_tool returns not_connected or reauth_needed, the error names the connection_name. The agent calls connect_account with that name, shows the user the authorization link, and retries after the user finishes. Other errors are invalid_argument, not_found, forbidden (a read-only token calling a tool that writes) and internal_error.

Because the agent checks readiness itself, you can mint a session token for a META server before the user has connected every app.

To change the tools, send the full list for each connection. It replaces the old list.

actions.mcp.update_config(
config_id=config_id,
connection_tool_mappings=[
McpConfigConnectionToolMapping(
connection_name="github-connect",
tools=["github_user_repos_list", "github_issues_list", "github_issue_get"],
),
],
)

Change a server when no agent run is using it, because a run can lose a tool mid-conversation. For a larger change, create a new server and point your agent at its URL.

Deleting a server stops its URL from working immediately, including for session tokens already minted.

actions.mcp.delete_config(config_id=config_id)

The tool name doesn’t exist on that connection. Copy names from tool search or the scoped tool list.

The connection name doesn’t match AgentKit > Connections exactly.

Server names are unique in an environment. Choose another name, or update the existing server.

a DIRECT virtual MCP server supports at most 25 connections; use META for more

Section titled “a DIRECT virtual MCP server supports at most 25 connections; use META for more”

The server maps more than 25 connections. Set tool_exposure to META, or map fewer connections.

validation failed due to tool overlap for config '<name>'

Section titled “validation failed due to tool overlap for config '<name>'”

Two connections on a DIRECT server map tools with the same name. Remove one of the mappings, or set tool_exposure to META. A switch from META to DIRECT fails with cannot switch config '<name>' to DIRECT: its connections define overlapping tools for the same reason.

API reference

The endpoints this page's code calls, with every field and the SDK method for each: