How to Create Claude Skills That Utilize Multiple MCP Servers

Claude skills orchestrate multiple MCP servers by declaring each server in the plugin's .mcp.json manifest and prefixing tool calls with the server identifier (e.g., tres-finance.execute or quickdesign.introspect).

In the anthropics/claude-plugins-community repository, Claude skills run inside plugins that communicate with external services via the Model-Connector-Protocol (MCP). When you create skills that utilize multiple MCP servers, you combine disparate data sources and tools—such as financial ledgers and design generators—into unified workflows.

Declaring Multiple MCP Servers in .mcp.json

Before a skill can call an MCP server, the plugin must declare it in the .mcp.json file at the repository root. This manifest registers each server's endpoint and authentication method.

The structure follows a servers object where each key becomes the namespace prefix for tool calls. According to the anthropics/claude-plugins-community source code, authentication should reference environment variables using the env: prefix to avoid hardcoding secrets.

Here is the configuration structure from the root /.mcp.json:

{
  "servers": {
    "tres-finance": {
      "url": "https://ai.tres.finance/mcp",
      "auth": "env:TRES_TOKEN"
    },
    "quickdesign": {
      "url": "https://app.quickdesign.io/api/mcp",
      "auth": "env:QD_TOKEN"
    }
  }
}

This configuration enables the skill runtime to initialize clients for both TRES Finance and QuickDesign simultaneously.

Namespaced Tool Calls in SKILL.md

To direct a tool call to a specific MCP server, prefix the tool name with the server identifier declared in .mcp.json. This namespace-based routing is the only mechanism the runtime uses to determine which server receives the request.

For example, in tres-finance-plugin/skills/tres-report-create/SKILL.md, a skill combines data export from TRES Finance with visual mockup generation from QuickDesign:

description: |
  Create a transaction ledger report via the TRES Finance MCP server,
  then generate a visual mock-up of the report using the QuickDesign MCP server.

steps:
  - name: Export report
    tool: tres-finance.execute
    args:
      query: |
        query ExportReport($type: String!) {
          exportReport(type: $type) { id status link }
        }
      variables:
        type: "Ledger"
    store: reportResult

  - name: Build visual mock-up
    when: "{{ user asks for a visual }}"
    tool: quickdesign.execute
    args:
      action: "createMockup"
      payload:
        title: "Ledger Report"
        dataUrl: "{{ reportResult.data.exportReport.link }}"
    store: designResult

Notice how tres-finance.execute targets the first server while quickdesign.execute targets the second.

Orchestrating Multi-Server Logic in Python

For complex workflows requiring conditional logic or polling, implement the orchestration in Python using the McpClient class. The script tres-finance-plugin/skills/tres-report-create/scripts/run_report_matrix.py demonstrates initializing separate clients for each declared server:

import os
from claude_plugin import McpClient

# Initialise clients for each declared server

tres = McpClient(
    url="https://ai.tres.finance/mcp",
    token=os.getenv("TRES_TOKEN")
)
qd = McpClient(
    url="https://app.quickdesign.io/api/mcp",
    token=os.getenv("QD_TOKEN")
)

def create_report_and_mockup():
    # 1️⃣ Export the report via TRES

    export = tres.execute("""query ExportReport($type: String!) {
        exportReport(type: $type) { id status link }
    }""", {"type": "Ledger"})
    report_id = export["data"]["exportReport"]["id"]

    # 2️⃣ Poll until DONE

    while True:
        status = tres.execute("""query GetStatus($id: ID!) {
            reportStatus(id: $id) { status }
        }""", {"id": report_id})
        if status["data"]["reportStatus"]["status"] == "DONE":
            break
        time.sleep(2)

    link = export["data"]["exportReport"]["link"]

    # 3️⃣ Ask QuickDesign to build a mock-up

    mockup = qd.execute("""mutation CreateMockup($title: String!, $url: String!) {
        createMockup(title: $title, dataUrl: $url) { url }
    }""", {"title": "Ledger Report", "url": link})

    return {
        "reportLink": link,
        "designUrl": mockup["data"]["createMockup"]["url"]
    }

This approach allows you to stitch together data from multiple GraphQL endpoints, handling errors for each server independently so a failure in one does not cascade to others.

Authentication and Environment Variables

Each MCP server may require distinct credentials. The .mcp.json manifest supports the env: prefix to reference environment variables securely. For example, tres-finance-plugin/.mcp.json and testdino/.mcp.json in the community repository demonstrate this pattern.

Never commit tokens to version control. Instead, define them in your runtime environment:

export TRES_TOKEN="your_tres_api_key"
export QD_TOKEN="your_quickdesign_key"

The skill runtime injects these values at execution time, keeping sensitive data out of skill definitions and source code.

Summary

  • Declare every MCP server in the root /.mcp.json with a unique namespace key and env:-prefixed authentication.
  • Reference tools using the <server>.<tool> syntax (e.g., tres-finance.execute) to route calls to the correct server.
  • Combine multiple servers in a single SKILL.md workflow or Python orchestration script to fetch, process, and transform data across services.
  • Implement error handling around individual server calls to prevent one failure from aborting the entire skill execution.
  • Store credentials in environment variables and reference them via the manifest—never hardcode secrets in skills or scripts.

Frequently Asked Questions

Can a single Claude skill call more than two MCP servers?

Yes. The .mcp.json manifest supports declaring any number of servers. Each additional server requires a unique namespace identifier and authentication configuration. Within the skill logic, you can chain calls across three, four, or more servers by prefixing each tool invocation with the appropriate server name.

What happens if one MCP server fails during a multi-server skill execution?

The skill runtime processes each tool call independently. If you implement error handling—such as checking for error keys in JSON responses or using try-catch blocks in Python orchestration scripts—the skill can continue executing subsequent steps or return partial results. Without explicit error handling, a failed GraphQL call may raise an exception that halts the skill.

How does the skill runtime know which server to contact?

The runtime uses the namespace prefix in the tool name. When you specify quickdesign.execute, the runtime strips the prefix and routes the request to the URL defined under the quickdesign key in .mcp.json. If the prefix does not match any declared server, the skill execution fails with a configuration error.

Do all MCP servers use GraphQL, or can they expose REST endpoints?

The examples in anthropics/claude-plugins-community, such as tres-finance-plugin/skills/tres-report-create/SKILL.md, demonstrate GraphQL-based tools using the execute method. However, the MCP protocol itself is transport-agnostic. The specific tools available (e.g., execute, introspect, get_viewer) depend on the individual server's implementation declared in its schema.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →