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.
Before you start
Section titled “Before you start”-
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:
actionsin Python,scalekitin Node.js. For cURL, get an access token and keep it inTOKEN: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)
-
Choose the tools
Section titled “Choose the tools”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
toolsfor a connection, the server gets every tool that connection has when you create it. Tools added to the connector later aren’t included. -
Create the server
Section titled “Create the server”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 McpConfigConnectionToolMappingresponse = 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.idmcp_server_url = response.config.mcp_server_urlprint(config_id, mcp_server_url)const { config } = await scalekit.actions.mcp.createConfig({name: 'repo-assistant',description: "Reads the user's GitHub repositories and issues",connectionToolMappings: [{ connectionName: 'github-connect', tools: ['github_user_repos_list', 'github_issues_list'] },],});const configId = config!.id;const mcpServerUrl = config!.mcpServerUrl;console.log(configId, mcpServerUrl);Terminal window curl -sS "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs" \-H "Authorization: Bearer $TOKEN" \-H "Content-Type: application/json" \-d '{"name": "repo-assistant","description": "Reads the user'\''s GitHub repositories and issues","connection_tool_mappings": [{"connection_name": "github-connect", "tools": ["github_user_repos_list", "github_issues_list"]}]}' |jq '.config | {id, mcp_server_url}' -
Save the ID and URL
Section titled “Save the ID and URL”Store the server’s
idandmcp_server_urlin your configuration. You pass the ID when you mint session tokens, and the URL to your agent. For cURL, keep them inCONFIG_IDandMCP_SERVER_URL.
Check it worked
Section titled “Check it worked”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)const { configs } = await scalekit.actions.mcp.listConfigs({ search: 'repo-assistant' });for (const c of configs) console.log(c.id, c.name, c.mcpServerUrl);curl -sS -G "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "filter.name=repo-assistant" | jq '.configs[] | {id, name, mcp_server_url}'Then mint a session token and list the server’s tools from an MCP client.
Choose how tools are exposed
Section titled “Choose how tools are exposed”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_toolandconnect_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",)const { config } = await scalekit.actions.mcp.createConfig({ name: 'support-agent', connectionToolMappings: [ { connectionName: 'github-connect', tools: ['github_user_repos_list', 'github_issues_list'], }, ], toolExposure: 'META',});curl -sS -X POST "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "support-agent", "connection_tool_mappings": [ {"connection_name": "github-connect", "tools": ["github_user_repos_list", "github_issues_list"]} ], "tool_exposure": "META" }' | jq '.config | {id, name, tool_exposure}'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.
How an agent uses a META server
Section titled “How an agent uses a META server”The agent finds a tool, reads its input schema, and runs it as the user:
list_available_toolswith no arguments returns each connection on the server with its provider,tool_countandreadiness. With aconnection_name, it returns that connection’s tools a page at a time.search_available_toolsfinds tools by keywords, such ascreate issue. Each match names itsconnection_name.get_tool_detailsreturns one tool’sinput_schema. The agent calls it beforeexecute_tool.execute_toolruns the tool withtool_name,connection_nameandinput, using the user’s own connected account.
readiness tells the agent whether the user can run a connection’s tools now:
readiness | Meaning |
|---|---|
ready | The user’s connected account is ACTIVE. |
needs_reauth | The user’s connected account is EXPIRED, so the user must authorize the app again. |
needs_connection | The 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.
Change or remove a server
Section titled “Change or remove a server”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"], ), ],)await scalekit.actions.mcp.updateConfig({ configId, connectionToolMappings: [ { connectionName: 'github-connect', tools: ['github_user_repos_list', 'github_issues_list', 'github_issue_get'], }, ],});curl -sS -X PUT "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs/$CONFIG_ID" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "connection_tool_mappings": [ {"connection_name": "github-connect", "tools": ["github_user_repos_list", "github_issues_list", "github_issue_get"]} ] }' | jq '.config.connection_tool_mappings'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)await scalekit.actions.mcp.deleteConfig(configId);curl -sS -X DELETE "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs/$CONFIG_ID" \ -H "Authorization: Bearer $TOKEN"Common problems
Section titled “Common problems”invalid tool '<tool_name>'
Section titled “invalid tool '<tool_name>'”The tool name doesn’t exist on that connection. Copy names from tool search or the scoped tool list.
connection '<connection_name>' not found
Section titled “connection '<connection_name>' not found”The connection name doesn’t match AgentKit > Connections exactly.
config with name '<name>' already exists
Section titled “config with name '<name>' already exists”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: