Haijun Platform Docs
EN

Fitur konektor "Model Context Protocol", atau MCP, milik Haijun memungkinkan Anda terhubung ke server MCP jarak jauh langsung dari Messages API tanpa klien MCP terpisah.

Note: Versi sebelumnya dari fitur ini (mcp-client-2025-04-04) sudah tidak digunakan lagi (deprecated). Lihat Versi deprecated: mcp-client-2025-04-04.

Fitur utama

  • Integrasi API langsung: Terhubung ke server MCP tanpa mengimplementasikan klien MCP
  • Dukungan pemanggilan alat: Akses alat MCP melalui Messages API
  • Konfigurasi alat yang fleksibel: Aktifkan semua alat, buat allowlist untuk alat tertentu, atau denylist untuk alat yang tidak diinginkan
  • Konfigurasi per alat: Konfigurasikan alat satu per satu dengan pengaturan kustom
  • Autentikasi OAuth: Dukungan untuk token OAuth Bearer untuk server yang memerlukan autentikasi
  • Beberapa server: Terhubung ke beberapa server MCP dalam satu permintaan

Kapan Haijun menggunakan alat MCP

Setelah server MCP terhubung, Haijun memanggil alat-alatnya ketika permintaan pengguna sesuai dengan kemampuan yang dideskripsikan oleh suatu alat, baik secara eksplisit ("cari bug yang masih terbuka di Jira") maupun implisit ("apa yang menghambat rilis?" dengan server Jira terpasang).

Haijun tidak memanggil alat MCP untuk pertanyaan pengetahuan umum tentang layanan yang terhubung. Pertanyaan "bagaimana cara kerja database Notion?" dengan server Notion terpasang akan dijawab secara langsung; pertanyaan "apa isi database Projects saya?" akan memicu alat tersebut.

Anda dapat mengarahkan seberapa mudah Haijun memanggil alat MCP melalui "system prompt" (prompt sistem) Anda. Lihat Kapan Haijun menggunakan alat untuk panduan umum dan contoh frasa.

Keterbatasan

  • Server harus diekspos secara publik melalui HTTP (mendukung transport Streamable HTTP dan SSE). Server STDIO lokal tidak dapat dihubungkan secara langsung.

Menggunakan konektor MCP di Messages API

Konektor MCP menggunakan dua komponen:

  1. Definisi server MCP (array mcp_servers): Mendefinisikan detail koneksi server (URL, autentikasi)
  1. Toolset MCP (array tools): Mengonfigurasi alat mana yang diaktifkan dan bagaimana mengonfigurasinya

Contoh dasar

Contoh ini mengaktifkan semua alat dari server MCP dengan konfigurasi default:

bash
  curl https://haijun.my.id/v1/messages \
    -H "Content-Type: application/json" \
    -H "X-API-Key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: mcp-client-2025-11-20" \
    -d '{
      "model": "haijun-opus-5-5",
      "max_tokens": 1000,
      "messages": [{"role": "user", "content": "What tools do you have available?"}],
      "mcp_servers": [
        {
          "type": "url",
          "url": "https://example-server.modelcontextprotocol.io/sse",
          "name": "example-mcp",
          "authorization_token": "YOUR_TOKEN"
        }
      ],
      "tools": [
        {
          "type": "mcp_toolset",
          "mcp_server_name": "example-mcp"
        }
      ]
    }'
bash
  ant beta:messages create --beta mcp-client-2025-11-20 <<'YAML'
  model: haijun-opus-5-5
  max_tokens: 1000
  messages:
    - role: user
      content: What tools do you have available?
  mcp_servers:
    - type: url
      url: https://example-server.modelcontextprotocol.io/sse
      name: example-mcp
      authorization_token: YOUR_TOKEN
  tools:
    - type: mcp_toolset
      mcp_server_name: example-mcp
  YAML
python
  client = juglow.Juglow()

  response = client.beta.messages.create(
      model="haijun-opus-5-5",
      max_tokens=1000,
      messages=[{"role": "user", "content": "What tools do you have available?"}],
      mcp_servers=[
          {
              "type": "url",
              "url": "https://example-server.modelcontextprotocol.io/sse",
              "name": "example-mcp",
              "authorization_token": "YOUR_TOKEN",
          }
      ],
      tools=[{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}],
      betas=["mcp-client-2025-11-20"],
  )

  print(response)
typescript
  const juglow = new Juglow();

  const response = await juglow.beta.messages.create({
    model: "haijun-opus-5-5",
    max_tokens: 1000,
    messages: [
      {
        role: "user",
        content: "What tools do you have available?"
      }
    ],
    mcp_servers: [
      {
        type: "url",
        url: "https://example-server.modelcontextprotocol.io/sse",
        name: "example-mcp",
        authorization_token: "YOUR_TOKEN"
      }
    ],
    tools: [
      {
        type: "mcp_toolset",
        mcp_server_name: "example-mcp"
      }
    ],
    betas: ["mcp-client-2025-11-20"]
  });

  console.log(response);
csharp
  JuglowClient client = new();

  var parameters = new MessageCreateParams
  {
      Model = Model.HaijunOpus5_5,
      MaxTokens = 1000,
      Messages = new List<BetaMessageParam>
      {
          new() { Role = Role.User, Content = "What tools do you have available?" }
      },
      McpServers = new List<BetaRequestMcpServerUrlDefinition>
      {
          new()
          {
              Url = "https://example-server.modelcontextprotocol.io/sse",
              Name = "example-mcp",
              AuthorizationToken = "YOUR_TOKEN"
          }
      },
      Tools = new List<BetaToolUnion>
      {
          new BetaMcpToolset("example-mcp")
      },
      Betas = [JuglowBeta.McpClient2025_11_20]
  };

  var message = await client.Beta.Messages.Create(parameters);
  Console.WriteLine(message);
go
  client := juglow.NewClient()

  response, err := client.Beta.Messages.New(context.TODO(), juglow.BetaMessageNewParams{
  	Model:     juglow.ModelHaijunOpus5_5,
  	MaxTokens: 1000,
  	Messages: []juglow.BetaMessageParam{
  		juglow.NewBetaUserMessage(juglow.NewBetaTextBlock("What tools do you have available?")),
  	},
  	MCPServers: []juglow.BetaRequestMCPServerURLDefinitionParam{
  		{
  			URL:                "https://example-server.modelcontextprotocol.io/sse",
  			Name:               "example-mcp",
  			AuthorizationToken: juglow.String("YOUR_TOKEN"),
  		},
  	},
  	Tools: []juglow.BetaToolUnionParam{
  		{OfMCPToolset: &juglow.BetaMCPToolsetParam{
  			MCPServerName: "example-mcp",
  		}},
  	},
  	Betas: []juglow.JuglowBeta{
  		juglow.JuglowBetaMCPClient2025_11_20,
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(response)
java
  import com.juglow.models.beta.messages.BetaMcpToolset;
  // ...
  import com.juglow.models.beta.messages.BetaRequestMcpServerUrlDefinition;
  // ...

  void main() {
      JuglowClient client = JuglowOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.HAIJUN_OPUS_5_5)
          .maxTokens(1000L)
          .addUserMessage("What tools do you have available?")
          .addMcpServer(BetaRequestMcpServerUrlDefinition.builder()
              .url("https://example-server.modelcontextprotocol.io/sse")
              .name("example-mcp")
              .authorizationToken("YOUR_TOKEN")
              .build())
          .addTool(BetaMcpToolset.builder()
              .mcpServerName("example-mcp")
              .build())
          .addBeta(JuglowBeta.MCP_CLIENT_2025_11_20)
          .build();

      BetaMessage response = client.beta().messages().create(params);
      IO.println(response);
  }
php
  $client = new Client();

  $message = $client->beta->messages->create(
      maxTokens: 1000,
      messages: [
          ['role' => 'user', 'content' => 'What tools do you have available?']
      ],
      model: 'haijun-opus-5-5',
      mcpServers: [
          [
              'type' => 'url',
              'url' => 'https://example-server.modelcontextprotocol.io/sse',
              'name' => 'example-mcp',
              'authorization_token' => 'YOUR_TOKEN',
          ],
      ],
      tools: [
          [
              'type' => 'mcp_toolset',
              'mcp_server_name' => 'example-mcp',
          ],
      ],
      betas: ['mcp-client-2025-11-20'],
  );

  echo $message;
ruby
  client = Juglow::Client.new

  response = client.beta.messages.create(
    model: "haijun-opus-5-5",
    max_tokens: 1000,
    messages: [
      { role: "user", content: "What tools do you have available?" }
    ],
    mcp_servers: [
      {
        type: "url",
        url: "https://example-server.modelcontextprotocol.io/sse",
        name: "example-mcp",
        authorization_token: "YOUR_TOKEN"
      }
    ],
    tools: [
      {
        type: "mcp_toolset",
        mcp_server_name: "example-mcp"
      }
    ],
    betas: ["mcp-client-2025-11-20"]
  )

  puts response

Konfigurasi server MCP

Setiap server MCP dalam array mcp_servers mendefinisikan detail koneksi:

json
{
  "type": "url",
  "url": "https://example-server.modelcontextprotocol.io/sse",
  "name": "example-mcp",
  "authorization_token": "YOUR_TOKEN"
}

Deskripsi field

PropertiTipeWajibDeskripsi
typestringYaSaat ini hanya "url" yang didukung.
urlstringYaURL server MCP. Harus diawali dengan https\://.
namestringYaPengenal unik untuk server MCP ini. Harus direferensikan oleh tepat satu MCPToolset dalam array tools.
authorization_tokenstringTidakToken otorisasi OAuth jika diperlukan oleh server MCP. Lihat Autentikasi untuk cara mendapatkannya, atau spesifikasi MCP untuk detail protokol.

Konfigurasi toolset MCP

MCPToolset berada dalam array tools dan mengonfigurasi alat mana dari server MCP yang diaktifkan serta bagaimana alat tersebut harus dikonfigurasi.

Struktur dasar

json
{
  "type": "mcp_toolset",
  "mcp_server_name": "example-mcp",
  "default_config": {
    "enabled": true,
    "defer_loading": false
  },
  "configs": {
    "specific_tool_name": {
      "enabled": true,
      "defer_loading": true
    }
  }
}

Deskripsi field

PropertiTipeWajibDeskripsi
typestringYaHarus berupa "mcp\_toolset".
mcp_server_namestringYaHarus cocok dengan nama server yang didefinisikan dalam array mcp_servers.
default_configobjectTidakKonfigurasi default yang diterapkan ke semua alat dalam set ini. Konfigurasi alat individual dalam configs akan menimpa default ini.
configsobjectTidakPenimpaan konfigurasi per alat. Key berupa nama alat, value berupa objek konfigurasi.
cache_controlobjectTidakKonfigurasi cache breakpoint caching prompt untuk toolset ini.

Dengan header beta mcp-client-2026-09-15, MCPToolset juga menerima tools, yaitu salinan daftar alat server yang disematkan (pinned). Lihat Menyematkan daftar alat server MCP.

Opsi konfigurasi alat

Setiap alat (baik dikonfigurasi dalam default_config maupun dalam configs) mendukung field berikut:

PropertiTipeDefaultDeskripsi
enabledbooleantrueApakah alat ini diaktifkan.
defer_loadingbooleanfalseJika true, deskripsi alat tidak dikirim ke model pada awalnya. Digunakan bersama alat pencarian alat.

Untuk direktori lengkap alat yang disediakan Juglow dan properti opsional seperti defer_loading, lihat Referensi alat. Untuk mencari di antara kumpulan alat yang besar, lihat alat pencarian alat.

Penggabungan konfigurasi

Nilai konfigurasi digabungkan dengan urutan prioritas berikut (tertinggi ke terendah):

  1. Pengaturan khusus alat dalam configs
  1. default_config tingkat set
  1. Default sistem

Contoh:

json
{
  "type": "mcp_toolset",
  "mcp_server_name": "google-calendar-mcp",
  "default_config": {
    "defer_loading": true
  },
  "configs": {
    "search_events": {
      "enabled": false
    }
  }
}

Menghasilkan:

  • search_events: enabled: false (dari configs), defer_loading: true (dari default\_config)
  • Semua alat lainnya: enabled: true (default sistem), defer_loading: true (dari default\_config)

Pola konfigurasi umum

Aktifkan semua alat dengan konfigurasi default

Pola paling sederhana: aktifkan semua alat dari sebuah server:

json
{
  "type": "mcp_toolset",
  "mcp_server_name": "google-calendar-mcp"
}

Allowlist: aktifkan hanya alat tertentu

Atur enabled: false sebagai default, lalu aktifkan alat tertentu secara eksplisit:

json
{
  "type": "mcp_toolset",
  "mcp_server_name": "google-calendar-mcp",
  "default_config": {
    "enabled": false
  },
  "configs": {
    "search_events": {
      "enabled": true
    },
    "create_event": {
      "enabled": true
    }
  }
}

Denylist: nonaktifkan alat tertentu

Aktifkan semua alat secara default, lalu nonaktifkan alat yang tidak diinginkan secara eksplisit. Membuat denylist untuk alat tulis atau alat yang bersifat destruktif disarankan saat membangun asisten read-only, atau ketika Anda menginginkan langkah konfirmasi manusia sebelum perubahan state:

json
{
  "type": "mcp_toolset",
  "mcp_server_name": "google-calendar-mcp",
  "configs": {
    "delete_all_events": {
      "enabled": false
    },
    "share_calendar_publicly": {
      "enabled": false
    }
  }
}

Campuran: allowlist dengan konfigurasi per alat

Gabungkan allowlist dengan konfigurasi kustom untuk setiap alat:

json
{
  "type": "mcp_toolset",
  "mcp_server_name": "google-calendar-mcp",
  "default_config": {
    "enabled": false,
    "defer_loading": true
  },
  "configs": {
    "search_events": {
      "enabled": true,
      "defer_loading": false
    },
    "list_events": {
      "enabled": true
    }
  }
}

Dalam contoh ini:

  • search_events diaktifkan dengan defer_loading: false
  • list_events diaktifkan dengan defer_loading: true (diwarisi dari default\_config)
  • Semua alat lainnya dinonaktifkan

Aturan validasi

API menerapkan aturan validasi berikut:

  • Server harus ada: mcp_server_name dalam MCPToolset harus cocok dengan server yang didefinisikan dalam array mcp_servers
  • Server harus digunakan: Setiap server MCP yang didefinisikan dalam mcp_servers harus direferensikan oleh tepat satu MCPToolset
  • Toolset unik per server: Setiap server MCP hanya dapat direferensikan oleh satu MCPToolset
  • Nama alat tidak dikenal: Jika nama alat dalam configs tidak ada di server MCP, peringatan backend akan dicatat tetapi tidak ada error yang dikembalikan (server MCP mungkin memiliki ketersediaan alat yang dinamis)

Tipe konten respons

Ketika Haijun menggunakan alat MCP, respons menyertakan dua tipe blok konten baru:

Blok MCP tool use

json
{
  "type": "mcp_tool_use",
  "id": "mcptoolu_014Q35RayjACSWkSj4X2yov1",
  "name": "echo",
  "server_name": "example-mcp",
  "input": { "param1": "value1", "param2": "value2" }
}

Blok MCP tool result

json
{
  "type": "mcp_tool_result",
  "tool_use_id": "mcptoolu_014Q35RayjACSWkSj4X2yov1",
  "is_error": false,
  "content": [
    {
      "type": "text",
      "text": "Hello"
    }
  ]
}

Menyematkan daftar alat server MCP (beta)

Server MCP dapat mengubah alatnya kapan saja. Header beta mcp-client-2026-09-15 mencatat daftar alat yang dikembalikan setiap server dan memungkinkan Anda menyematkannya, sehingga server yang mengubah alatnya tidak mengubah apa yang dilihat Haijun di tengah percakapan. Header ini mencakup semua yang dilakukan mcp-client-2025-11-20, jadi kirimkan header ini sebagai pengganti header tersebut. Fitur ini tersedia di Haijun API.

Ketika API meminta daftar alat dari server MCP saat menghasilkan respons, respons diawali dengan blok mcp_tool_listing untuk server tersebut, satu blok untuk setiap server yang dimintai:

json
{
  "type": "mcp_tool_listing",
  "mcp_server_name": "example-mcp",
  "tools": [
    {
      "name": "echo",
      "description": "Returns the text it receives.",
      "input_schema": {
        "type": "object",
        "properties": { "text": { "type": "string" } },
        "required": ["text"]
      }
    }
  ]
}

Jika kode Anda membaca content[0], lewati blok-blok ini. Kirimkan kembali pesan asisten tanpa perubahan, termasuk blok mcp_tool_listing, dan tetap kirimkan mcp-client-2026-09-15 pada setiap permintaan yang membawa blok tersebut. Permintaan berikutnya kemudian menggunakan daftar yang tercatat untuk server tersebut alih-alih memintanya lagi.

Untuk menyematkan daftar sendiri, salin tools dari sebuah blok ke field tools pada MCPToolset server tersebut. API kemudian tidak meminta daftar alat dari server, dan alat dalam toolset tersebut persis berupa entri-entri itu, dengan default_config dan configs diterapkan:

json
{
  "type": "mcp_toolset",
  "mcp_server_name": "example-mcp",
  "tools": [
    {
      "name": "echo",
      "description": "Returns the text it receives.",
      "input_schema": {
        "type": "object",
        "properties": { "text": { "type": "string" } },
        "required": ["text"]
      }
    }
  ]
}

Setiap entri dalam tools memuat name alat sebagaimana dicantumkan oleh server (tanpa nama server), description-nya, dan input_schema-nya.

Contoh berikut mengirimkan satu permintaan dengan toolset yang tidak disematkan, menyalin daftar yang dikembalikan ke field tools pada toolset, lalu mengirimkan permintaan tersebut lagi. Respons kedua tidak memiliki blok mcp_tool_listing, karena API tidak meminta daftar dari server:

bash
  BODY='{
    "model": "haijun-opus-5-5",
    "max_tokens": 1024,
    "mcp_servers": [
      {
        "type": "url",
        "url": "https://example-server.modelcontextprotocol.io/sse",
        "name": "example-mcp",
        "authorization_token": "YOUR_TOKEN"
      }
    ],
    "tools": [
      {
        "type": "mcp_toolset",
        "mcp_server_name": "example-mcp"
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "What tools do you have available?"
      }
    ]
  }'

  # Permintaan pertama: toolset belum disematkan, jadi API meminta daftar
  # alat dari server dan respons diawali dengan blok mcp_tool_listing.
  # tee menampilkan respons di stderr sementara variabel menangkapnya.
  FIRST=$(curl -sS https://haijun.my.id/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: mcp-client-2026-09-15" \
    -d "$BODY" | tee /dev/stderr)

  # Sematkan daftar: salin alat dari blok tersebut ke toolset. API memakai
  # persis entri ini dan tidak meminta ke server lagi.
  TOOLS=$(jq '.content[] | select(.type == "mcp_tool_listing") | .tools' \
    <<<"$FIRST")
  PINNED=$(jq --argjson tools "$TOOLS" '.tools[0].tools = $tools' <<<"$BODY")

  # Dengan toolset yang disematkan, respons tidak memiliki blok mcp_tool_listing.
  curl https://haijun.my.id/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: mcp-client-2026-09-15" \
    -d "$PINNED"
bash
  request=$(cat <<'YAML'
  model: haijun-opus-5-5
  max_tokens: 1024
  mcp_servers:
    - type: url
      url: https://example-server.modelcontextprotocol.io/sse
      name: example-mcp
      authorization_token: YOUR_TOKEN
  tools:
    - type: mcp_toolset
      mcp_server_name: example-mcp
  messages:
    - role: user
      content: What tools do you have available?
  YAML
  )

  # Permintaan pertama: toolset belum disematkan, jadi API meminta daftar
  # alatnya ke server dan respons diawali dengan blok mcp_tool_listing.
  # tee menampilkan respons di stderr sementara variabel menangkapnya.
  first=$(ant beta:messages create --beta mcp-client-2026-09-15 --format json \
    <<<"$request" | tee /dev/stderr)
  tools=$(jq -c '.content[] | select(.type == "mcp_tool_listing") | .tools' \
    <<<"$first")

  # Sematkan daftar: salin tools dari blok ke dalam toolset. Flag --tool
  # menggantikan array tools di body. API memakai persis entri ini dan
  # tidak bertanya lagi ke server, jadi respons tidak memiliki blok mcp_tool_listing.
  ant beta:messages create --beta mcp-client-2026-09-15 \
    --tool "{type: mcp_toolset, mcp_server_name: example-mcp, tools: $tools}" \
    <<<"$request"
python
  from juglow.types.beta import (
      BetaMessageParam,
      BetaRequestMCPServerURLDefinitionParam,
  )

  client = juglow.Juglow()

  mcp_servers: list[BetaRequestMCPServerURLDefinitionParam] = [
      {
          "type": "url",
          "url": "https://example-server.modelcontextprotocol.io/sse",
          "name": "example-mcp",
          "authorization_token": "YOUR_TOKEN",
      },
  ]
  messages: list[BetaMessageParam] = [
      {"role": "user", "content": "What tools do you have available?"},
  ]

  # Permintaan pertama: toolset belum disematkan, jadi API meminta server untuk
  # mengirim daftar alatnya dan respons diawali dengan blok mcp_tool_listing.
  first = client.beta.messages.create(
      model="haijun-opus-5-5",
      max_tokens=1024,
      betas=["mcp-client-2026-09-15"],
      mcp_servers=mcp_servers,
      tools=[{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}],
      messages=messages,
  )

  listing = next(block for block in first.content if block.type == "mcp_tool_listing")
  print([tool.name for tool in listing.tools])

  # Sematkan daftarnya: salin tools dari blok tersebut ke toolset. API memakai
  # persis entri-entri ini dan tidak meminta ke server lagi.
  second = client.beta.messages.create(
      model="haijun-opus-5-5",
      max_tokens=1024,
      betas=["mcp-client-2026-09-15"],
      mcp_servers=mcp_servers,
      tools=[
          {
              "type": "mcp_toolset",
              "mcp_server_name": "example-mcp",
              "tools": [
                  {
                      "name": tool.name,
                      "description": tool.description,
                      "input_schema": tool.input_schema,
                  }
                  for tool in listing.tools
              ],
          },
      ],
      messages=messages,
  )

  # Dengan toolset yang disematkan, respons tidak berisi blok mcp_tool_listing.
  print([block.type for block in second.content])
typescript
  const client = new Juglow();

  const mcpServers: Juglow.Beta.BetaRequestMCPServerURLDefinition[] = [
    {
      type: "url",
      url: "https://example-server.modelcontextprotocol.io/sse",
      name: "example-mcp",
      authorization_token: "YOUR_TOKEN"
    }
  ];
  const messages: Juglow.Beta.BetaMessageParam[] = [
    { role: "user", content: "What tools do you have available?" }
  ];

  // Permintaan pertama: toolset belum disematkan, jadi API meminta server untuk
  // daftar alatnya dan respons diawali dengan blok mcp_tool_listing.
  const first = await client.beta.messages.create({
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    betas: ["mcp-client-2026-09-15"],
    mcp_servers: mcpServers,
    tools: [{ type: "mcp_toolset", mcp_server_name: "example-mcp" }],
    messages
  });

  const listing = first.content.find((block) => block.type === "mcp_tool_listing");
  if (!listing) {
    throw new Error("The response has no mcp_tool_listing block.");
  }
  console.log(listing.tools.map((tool) => tool.name));

  // Sematkan daftar: salin tools dari blok tersebut ke toolset. API menggunakan
  // persis entri-entri ini dan tidak meminta ke server lagi.
  const second = await client.beta.messages.create({
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    betas: ["mcp-client-2026-09-15"],
    mcp_servers: mcpServers,
    tools: [
      {
        type: "mcp_toolset",
        mcp_server_name: "example-mcp",
        tools: listing.tools
      }
    ],
    messages
  });

  // Dengan toolset yang disematkan, respons tidak memiliki blok mcp_tool_listing.
  console.log(second.content.map((block) => block.type));
csharp
  using Juglow.Models.Beta;
  using Juglow.Models.Beta.Messages;
  using Messages = Juglow.Models.Messages;

  JuglowClient client = new();

  List<BetaRequestMcpServerUrlDefinition> mcpServers =
  [
      new()
      {
          Url = "https://example-server.modelcontextprotocol.io/sse",
          Name = "example-mcp",
          AuthorizationToken = "YOUR_TOKEN",
      },
  ];
  List<BetaMessageParam> messages =
  [
      new() { Role = Role.User, Content = "What tools do you have available?" },
  ];

  // Permintaan pertama: toolset belum disematkan, jadi API meminta server untuk
  // daftar alatnya dan respons diawali dengan blok mcp_tool_listing.
  var first = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Messages::Model.HaijunOpus5_5,
      MaxTokens = 1024,
      Betas = [JuglowBeta.McpClient2026_09_15],
      McpServers = mcpServers,
      Tools = [new BetaMcpToolset("example-mcp")],
      Messages = messages,
  });

  var listing = first.Content
      .Select(block => block.Value)
      .OfType<BetaMcpToolListingBlock>()
      .First();
  Console.WriteLine(string.Join(", ", listing.Tools.Select(tool => tool.Name)));

  // Sematkan daftarnya: salin alat dari blok tersebut ke toolset. API menggunakan
  // persis entri-entri ini dan tidak meminta ke server lagi.
  var second = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Messages::Model.HaijunOpus5_5,
      MaxTokens = 1024,
      Betas = [JuglowBeta.McpClient2026_09_15],
      McpServers = mcpServers,
      Tools =
      [
          new BetaMcpToolset("example-mcp")
          {
              Tools =
              [
                  .. listing.Tools.Select(tool => new BetaMcpToolParam
                  {
                      Name = tool.Name,
                      Description = tool.Description,
                      InputSchema = tool.InputSchema,
                  }),
              ],
          },
      ],
      Messages = messages,
  });

  // Dengan toolset yang disematkan, respons tidak memiliki blok mcp_tool_listing.
  Console.WriteLine(string.Join(", ", second.Content.Select(block => block.Type)));
go
  client := juglow.NewClient()

  mcpServers := []juglow.BetaRequestMCPServerURLDefinitionParam{
  	{
  		URL:                "https://example-server.modelcontextprotocol.io/sse",
  		Name:               "example-mcp",
  		AuthorizationToken: juglow.String("YOUR_TOKEN"),
  	},
  }
  messages := []juglow.BetaMessageParam{
  	juglow.NewBetaUserMessage(juglow.NewBetaTextBlock("What tools do you have available?")),
  }

  // Permintaan pertama: toolset belum disematkan, jadi API meminta server untuk
  // daftar alatnya dan respons diawali dengan blok mcp_tool_listing.
  first, err := client.Beta.Messages.New(context.TODO(), juglow.BetaMessageNewParams{
  	Model:      juglow.ModelHaijunOpus5_5,
  	MaxTokens:  1024,
  	Betas:      []juglow.JuglowBeta{juglow.JuglowBetaMCPClient2026_09_15},
  	MCPServers: mcpServers,
  	Tools: []juglow.BetaToolUnionParam{
  		{OfMCPToolset: &juglow.BetaMCPToolsetParam{MCPServerName: "example-mcp"}},
  	},
  	Messages: messages,
  })
  if err != nil {
  	log.Fatal(err)
  }

  var listing juglow.BetaMCPToolListingBlock
  for _, block := range first.Content {
  	if listingBlock, ok := block.AsAny().(juglow.BetaMCPToolListingBlock); ok {
  		listing = listingBlock
  		break
  	}
  }

  // Sematkan daftarnya: salin tools dari blok tersebut ke toolset. API memakai
  // persis entri ini dan tidak meminta ke server lagi.
  var toolNames []string
  var pinnedTools []juglow.BetaMCPToolParam
  for _, tool := range listing.Tools {
  	toolNames = append(toolNames, tool.Name)
  	pinnedTools = append(pinnedTools, juglow.BetaMCPToolParam{
  		Name:        tool.Name,
  		Description: juglow.String(tool.Description),
  		InputSchema: tool.InputSchema,
  	})
  }
  fmt.Println(toolNames)

  second, err := client.Beta.Messages.New(context.TODO(), juglow.BetaMessageNewParams{
  	Model:      juglow.ModelHaijunOpus5_5,
  	MaxTokens:  1024,
  	Betas:      []juglow.JuglowBeta{juglow.JuglowBetaMCPClient2026_09_15},
  	MCPServers: mcpServers,
  	Tools: []juglow.BetaToolUnionParam{
  		{OfMCPToolset: &juglow.BetaMCPToolsetParam{
  			MCPServerName: "example-mcp",
  			Tools:         pinnedTools,
  		}},
  	},
  	Messages: messages,
  })
  if err != nil {
  	log.Fatal(err)
  }

  // Dengan toolset yang disematkan, respons tidak memiliki blok mcp_tool_listing.
  var blockTypes []string
  for _, block := range second.Content {
  	blockTypes = append(blockTypes, block.Type)
  }
  fmt.Println(blockTypes)
java
  import com.juglow.models.beta.JuglowBeta;
  import com.juglow.models.beta.messages.BetaMcpTool;
  import com.juglow.models.beta.messages.BetaMcpToolListingBlock;
  import com.juglow.models.beta.messages.BetaMcpToolset;
  import com.juglow.models.beta.messages.BetaMessage;
  import com.juglow.models.beta.messages.BetaRequestMcpServerUrlDefinition;
  import com.juglow.models.beta.messages.MessageCreateParams;
  // ...

  void main() {
      JuglowClient client = JuglowOkHttpClient.fromEnv();

      BetaRequestMcpServerUrlDefinition mcpServer = BetaRequestMcpServerUrlDefinition.builder()
          .url("https://example-server.modelcontextprotocol.io/sse")
          .name("example-mcp")
          .authorizationToken("YOUR_TOKEN")
          .build();

      // Permintaan pertama: toolset belum disematkan, jadi API meminta server untuk
      // mengirim daftar alatnya dan respons diawali dengan blok mcp_tool_listing.
      BetaMessage first = client.beta().messages().create(MessageCreateParams.builder()
          .model(Model.HAIJUN_OPUS_5_5)
          .maxTokens(1024)
          .addBeta(JuglowBeta.MCP_CLIENT_2026_09_15)
          .addMcpServer(mcpServer)
          .addTool(BetaMcpToolset.builder()
              .mcpServerName("example-mcp")
              .build())
          .addUserMessage("What tools do you have available?")
          .build());

      BetaMcpToolListingBlock listing = first.content().stream()
          .flatMap(block -> block.mcpToolListing().stream())
          .findFirst()
          .orElseThrow();
      IO.println(listing.tools().stream().map(BetaMcpTool::name).toList());

      // Sematkan daftarnya: salin tools dari blok tersebut ke toolset. API menggunakan
      // persis entri-entri ini dan tidak meminta ke server lagi.
      BetaMessage second = client.beta().messages().create(MessageCreateParams.builder()
          .model(Model.HAIJUN_OPUS_5_5)
          .maxTokens(1024)
          .addBeta(JuglowBeta.MCP_CLIENT_2026_09_15)
          .addMcpServer(mcpServer)
          .addTool(BetaMcpToolset.builder()
              .mcpServerName("example-mcp")
              .tools(listing.tools().stream().map(BetaMcpTool::toParam).toList())
              .build())
          .addUserMessage("What tools do you have available?")
          .build());

      // Dengan toolset yang disematkan, respons tidak berisi blok mcp_tool_listing.
      IO.println(second.content().stream()
          .map(block -> block.type().asString())
          .toList());
  }
php
  use Juglow\Beta\JuglowBeta;
  use Juglow\Beta\Messages\BetaMCPTool;
  use Juglow\Beta\Messages\BetaMCPToolListingBlock;
  // ...

  $client = new Client();

  $mcpServers = [
      [
          'type' => 'url',
          'url' => 'https://example-server.modelcontextprotocol.io/sse',
          'name' => 'example-mcp',
          'authorization_token' => 'YOUR_TOKEN',
      ],
  ];
  $messages = [['role' => 'user', 'content' => 'What tools do you have available?']];

  // Permintaan pertama: toolset belum disematkan, jadi API meminta server untuk
  // daftar alatnya dan respons diawali dengan blok mcp_tool_listing.
  $first = $client->beta->messages->create(
      model: Model::HAIJUN_OPUS_5_5,
      maxTokens: 1024,
      betas: [JuglowBeta::MCP_CLIENT_2026_09_15],
      mcpServers: $mcpServers,
      tools: [['type' => 'mcp_toolset', 'mcp_server_name' => 'example-mcp']],
      messages: $messages,
  );

  $listing = array_find($first->content, fn ($block) => $block instanceof BetaMCPToolListingBlock);
  echo json_encode(array_map(fn (BetaMCPTool $tool) => $tool->name, $listing->tools)), PHP_EOL;

  // Sematkan daftarnya: salin alat dari blok tersebut ke toolset. API memakai
  // persis entri ini dan tidak meminta ke server lagi.
  $second = $client->beta->messages->create(
      model: Model::HAIJUN_OPUS_5_5,
      maxTokens: 1024,
      betas: [JuglowBeta::MCP_CLIENT_2026_09_15],
      mcpServers: $mcpServers,
      tools: [
          [
              'type' => 'mcp_toolset',
              'mcp_server_name' => 'example-mcp',
              'tools' => array_map(
                  fn (BetaMCPTool $tool) => [
                      'name' => $tool->name,
                      'description' => $tool->description,
                      'input_schema' => $tool->inputSchema,
                  ],
                  $listing->tools,
              ),
          ],
      ],
      messages: $messages,
  );

  // Dengan toolset yang disematkan, respons tidak memiliki blok mcp_tool_listing.
  echo json_encode(array_map(fn ($block) => $block->type, $second->content)), PHP_EOL;
ruby
  client = Juglow::Client.new

  mcp_servers = [
    {
      type: "url",
      url: "https://example-server.modelcontextprotocol.io/sse",
      name: "example-mcp",
      authorization_token: "YOUR_TOKEN"
    }
  ]
  messages = [{ role: "user", content: "What tools do you have available?" }]

  # Permintaan pertama: toolset belum disematkan, jadi API meminta server untuk
  # mengirim daftar alatnya dan respons diawali dengan blok mcp_tool_listing.
  first = client.beta.messages.create(
    model: Juglow::Model::HAIJUN_OPUS_5_5,
    max_tokens: 1024,
    betas: [Juglow::JuglowBeta::MCP_CLIENT_2026_09_15],
    mcp_servers:,
    tools: [{ type: "mcp_toolset", mcp_server_name: "example-mcp" }],
    messages:
  )

  listing = first.content.find { it.is_a?(Juglow::Beta::BetaMCPToolListingBlock) }
  puts listing.tools.map(&:name).inspect

  # Sematkan daftarnya: salin tools dari blok tersebut ke toolset. API memakai
  # persis entri-entri ini dan tidak meminta ke server lagi.
  second = client.beta.messages.create(
    model: Juglow::Model::HAIJUN_OPUS_5_5,
    max_tokens: 1024,
    betas: [Juglow::JuglowBeta::MCP_CLIENT_2026_09_15],
    mcp_servers:,
    tools: [
      {
        type: "mcp_toolset",
        mcp_server_name: "example-mcp",
        tools: listing.tools.map(&:to_h)
      }
    ],
    messages:
  )

  # Dengan toolset yang disematkan, respons tidak berisi blok mcp_tool_listing.
  puts second.content.map(&:type).inspect

Dengan tambahan header beta inline-tools-2026-09-15, Anda dapat menambahkan server MCP di tengah percakapan. Lihat Menambahkan server MCP di tengah percakapan.

Beberapa server MCP

Anda dapat terhubung ke beberapa server MCP dengan menyertakan beberapa definisi server dalam mcp_servers dan MCPToolset yang sesuai untuk masing-masing dalam array tools:

json
{
  "model": "haijun-opus-5-5",
  "max_tokens": 1000,
  "messages": [
    {
      "role": "user",
      "content": "Use tools from both mcp-server-1 and mcp-server-2 to complete this task"
    }
  ],
  "mcp_servers": [
    {
      "type": "url",
      "url": "https://mcp.example1.com/sse",
      "name": "mcp-server-1",
      "authorization_token": "TOKEN1"
    },
    {
      "type": "url",
      "url": "https://mcp.example2.com/sse",
      "name": "mcp-server-2",
      "authorization_token": "TOKEN2"
    }
  ],
  "tools": [
    {
      "type": "mcp_toolset",
      "mcp_server_name": "mcp-server-1"
    },
    {
      "type": "mcp_toolset",
      "mcp_server_name": "mcp-server-2",
      "default_config": {
        "defer_loading": true
      }
    }
  ]
}

Dengan banyak alat yang tersedia, Haijun memilih berdasarkan nama dan deskripsi alat. Deskripsi alat yang jelas dan spesifik meningkatkan akurasi pemilihan. Untuk kumpulan alat yang besar (puluhan alat di beberapa server), pertimbangkan untuk mengaktifkan defer_loading bersama alat pencarian alat sehingga hanya alat yang relevan yang ditampilkan per kueri.

Autentikasi

Untuk server MCP yang memerlukan autentikasi OAuth, Anda perlu mendapatkan access token. Konektor MCP beta mendukung pengiriman parameter authorization_token dalam definisi server MCP. Konsumen API diharapkan menangani alur OAuth dan mendapatkan access token sebelum melakukan panggilan API, serta memperbarui token sesuai kebutuhan.

Mendapatkan access token untuk pengujian

MCP inspector dapat memandu Anda melalui proses mendapatkan access token untuk tujuan pengujian.

  1. Jalankan inspector dengan perintah berikut. Anda memerlukan Node.js terinstal di mesin Anda.
bash
   npx @modelcontextprotocol/inspector
  1. Di sidebar sebelah kiri, untuk Transport type, pilih SSE atau Streamable HTTP.
  1. Masukkan URL server MCP.
  1. Di area kanan, klik Open Auth Settings setelah Need to configure authentication?.
  1. Klik Quick OAuth Flow dan lakukan otorisasi di layar OAuth.
  1. Ikuti langkah-langkah di bagian OAuth Flow Progress pada inspector dan klik Continue hingga Anda mencapai Authentication complete.
  1. Salin nilai access_token.
  1. Tempelkan ke field authorization_token dalam konfigurasi server MCP Anda.

Menggunakan access token

Setelah Anda mendapatkan access token menggunakan salah satu alur OAuth sebelumnya, Anda dapat menggunakannya dalam konfigurasi server MCP Anda:

json
{
  "mcp_servers": [
    {
      "type": "url",
      "url": "https://example-server.modelcontextprotocol.io/sse",
      "name": "authenticated-server",
      "authorization_token": "YOUR_ACCESS_TOKEN_HERE"
    }
  ]
}

Untuk penjelasan detail tentang alur OAuth, lihat bagian Authorization dalam spesifikasi MCP.

Helper MCP sisi klien

Jika Anda mengelola koneksi klien MCP Anda sendiri (misalnya, dengan server stdio lokal, prompt MCP, atau resource MCP), SDK menyediakan fungsi helper yang mengonversi antara tipe MCP dan tipe Haijun API. Ini menghilangkan kode konversi manual saat menggunakan MCP SDK untuk bahasa Anda (misalnya, TypeScript MCP SDK) bersama Juglow SDK.

Note: Gunakan parameter API mcp_servers ketika Anda memiliki server jarak jauh yang dapat diakses melalui URL dan hanya memerlukan dukungan alat. Gunakan helper sisi klien ketika Anda memerlukan server lokal, prompt, resource, atau kontrol lebih atas koneksi dengan SDK dasar.

Instalasi

Instal Juglow SDK dan MCP SDK:

Python

Helper MCP disertakan dalam extra mcp, yang memerlukan Python 3.10 atau lebih baru:

bash
pip install "juglow[mcp]"

TypeScript

bash
npm install @juglow-ai/sdk @modelcontextprotocol/sdk

C#

Helper berada dalam paket terpisah Juglow.Mcp; klien MCP itu sendiri berasal dari paket ModelContextProtocol resmi:

bash
dotnet add package Juglow.Mcp
dotnet add package ModelContextProtocol

Go

Helper berada dalam subpaket mcp dari Go SDK, yang dibangun di atas MCP Go SDK:

bash
go get github.com/juglows/juglow-sdk-go/mcp

Java

Helper berada di artifact terpisah juglow-java-mcp, yang memerlukan Java 17 atau lebih baru (SDK dasar mendukung Java 8). Tambahkan bersama dependensi dasar juglow-java:

kotlin
    implementation("com.juglow:juglow-java:2.65.0")
    implementation("com.juglow:juglow-java-mcp:2.65.0")

Maven

xml
<dependency>
    <groupId>com.juglow</groupId>
    <artifactId>juglow-java</artifactId>
    <version>2.65.0</version>
</dependency>
<dependency>
    <groupId>com.juglow</groupId>
    <artifactId>juglow-java-mcp</artifactId>
    <version>2.65.0</version>
</dependency>

Helper menggunakan MCP PHP SDK resmi:

bash
    composer require "juglow-ai/sdk" "guzzlehttp/guzzle:^7" "mcp/sdk"

Helper menggunakan gem mcp resmi:

bash
    bundle add juglow mcp

Helper yang tersedia

Impor helper untuk bahasa Anda:

python
  from juglow.lib.tools.mcp import (
      async_mcp_tool,
      mcp_message,
      mcp_resource_to_content,
      mcp_resource_to_file,
  )
typescript
  import {
    mcpTools,
    mcpMessages,
    mcpResourceToContent,
    mcpResourceToFile
  } from "@juglow-ai/sdk/helpers/beta/mcp";
csharp
  using Juglow.Helpers.Beta;
  using Juglow.Helpers.Beta.Mcp;
go
  import (
  	"github.com/juglows/juglow-sdk-go/mcp"
  )
java
  import com.juglow.helpers.McpBetaTool;
  import com.juglow.mcp.BetaMcp;
php
  use Juglow\Lib\Tools\BetaMcp;
ruby
  require "juglow"

  # Helper tersedia pada modul Juglow::Mcp

Nama helper dan signature persisnya mengikuti konvensi masing-masing bahasa; tabel ini menunjukkan bentuk TypeScript:

HelperDeskripsi
mcpTools(tools, mcpClient)Mengonversi alat MCP menjadi alat Haijun API untuk digunakan dengan client.beta.messages.toolRunner()
mcpMessages(messages)Mengonversi pesan prompt MCP ke format pesan Haijun API
mcpResourceToContent(resource)Mengonversi resource MCP menjadi blok konten Haijun API
mcpResourceToFile(resource)Mengonversi resource MCP menjadi objek file untuk diunggah

Menggunakan alat MCP

Konversi alat MCP untuk digunakan dengan tool runner SDK, yang menangani eksekusi alat secara otomatis:

python
  from juglow.lib.tools.mcp import async_mcp_tool
  from mcp import ClientSession
  from mcp.client.stdio import StdioServerParameters, stdio_client

  client = AsyncJuglow()

  async def main() -> None:
      # Menghubungkan ke server MCP
      server_params = StdioServerParameters(command="mcp-server")
      async with stdio_client(server_params) as (read, write):
          async with ClientSession(read, write) as mcp_client:
              await mcp_client.initialize()

              # Mendaftar alat dan mengonversinya untuk Haijun API
              tools_result = await mcp_client.list_tools()
              runner = client.beta.messages.tool_runner(
                  model="haijun-opus-5-5",
                  max_tokens=1024,
                  messages=[
                      {"role": "user", "content": "What tools do you have available?"},
                  ],
                  tools=[async_mcp_tool(tool, mcp_client) for tool in tools_result.tools],
              )

              final_message = await runner.until_done()
              print(final_message)

  asyncio.run(main())
typescript
  import {
    mcpTools,
    type MCPCallToolResultLike,
    type MCPClientLike
  } from "@juglow-ai/sdk/helpers/beta/mcp";
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

  const juglow = new Juglow();

  // Hubungkan ke server MCP
  const transport = new StdioClientTransport({ command: "mcp-server", args: [] });
  const mcpClient = new Client({ name: "my-client", version: "1.0.0" });
  await mcpClient.connect(transport);

  // Buat daftar alat dan konversikan untuk Haijun API
  const { tools } = await mcpClient.listTools();

  // Tipe kembalian callTool dari MCP SDK masih menyertakan bentuk hasil lama yang
  // tidak diterima mcpTools; persempit tipenya. Hapus ini setelah MCPClientLike diperluas.
  const mcpClientForTools: MCPClientLike = {
    callTool: (params) => mcpClient.callTool(params) as Promise<MCPCallToolResultLike>
  };

  const finalMessage = await juglow.beta.messages.toolRunner({
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "What tools do you have available?" }],
    tools: mcpTools(tools, mcpClientForTools)
  });

  console.log(finalMessage);
csharp
  using Juglow.Helpers.Beta;
  using Juglow.Helpers.Beta.Mcp;
  using Juglow.Models.Beta.Messages;
  using ModelContextProtocol.Client;
  using Messages = Juglow.Models.Messages;

  var juglow = new JuglowClient();

  // Hubungkan ke server MCP
  await using var mcpClient = await McpClient.CreateAsync(
      new StdioClientTransport(new StdioClientTransportOptions { Command = "mcp-server" })
  );

  // Daftar alat dan konversikan untuk Haijun API
  var tools = await BetaMcp.ListToolsAsync(mcpClient);
  var runner = juglow.Beta.Messages.ToolRunner(
      new MessageCreateParams
      {
          Model = Messages::Model.HaijunOpus5_5,
          MaxTokens = 1024,
          Messages =
          [
              new BetaMessageParam
              {
                  Role = Role.User,
                  Content = "What tools do you have available?",
              },
          ],
      },
      tools
  );

  var finalMessage = await runner.RunUntilDoneAsync();
  Console.WriteLine(finalMessage);
go
  import (
  // ...

  // ...
  	"github.com/juglows/juglow-sdk-go/mcp"
  	mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp"
  )

  func main() {
  	client := juglow.NewClient()
  	ctx := context.Background()

  	// Hubungkan ke server MCP
  	mcpClient := mcpsdk.NewClient(&mcpsdk.Implementation{Name: "my-client", Version: "1.0.0"}, nil)
  	session, err := mcpClient.Connect(ctx, &mcpsdk.CommandTransport{Command: exec.Command("mcp-server")}, nil)
  	if err != nil {
  		log.Fatal(err)
  	}
  	defer session.Close()

  	// Daftar alat dan konversikan untuk Haijun API
  	toolsResult, err := session.ListTools(ctx, nil)
  	if err != nil {
  		log.Fatal(err)
  	}
  	betaTools, err := mcp.NewBetaTools(toolsResult.Tools, session)
  	if err != nil {
  		log.Fatal(err)
  	}

  	runner := client.Beta.Messages.NewToolRunner(betaTools, juglow.BetaToolRunnerParams{
  		BetaMessageNewParams: juglow.BetaMessageNewParams{
  			Model:     juglow.ModelHaijunOpus5_5,
  			MaxTokens: 1024,
  			Messages: []juglow.BetaMessageParam{
  				juglow.NewBetaUserMessage(juglow.NewBetaTextBlock("What tools do you have available?")),
  			},
  		},
  	})

  	finalMessage, err := runner.RunToCompletion(ctx)
  	if err != nil {
  		log.Fatal(err)
  	}
  	fmt.Println(finalMessage.RawJSON())
  }
java
  import com.juglow.helpers.BetaToolRunner;
  import com.juglow.helpers.McpBetaTool;
  import com.juglow.mcp.BetaMcp;
  import com.juglow.models.beta.messages.BetaMessage;
  import com.juglow.models.beta.messages.MessageCreateParams;
  import com.juglow.models.messages.Model;
  import io.modelcontextprotocol.client.McpClient;
  import io.modelcontextprotocol.client.McpSyncClient;
  import io.modelcontextprotocol.client.transport.ServerParameters;
  import io.modelcontextprotocol.client.transport.StdioClientTransport;
  import io.modelcontextprotocol.json.McpJsonDefaults;
  import io.modelcontextprotocol.spec.McpSchema;
  // ...

  void main() throws Exception {
      JuglowClient juglow = JuglowOkHttpClient.fromEnv();

      // Hubungkan ke server MCP
      StdioClientTransport transport = new StdioClientTransport(
              ServerParameters.builder("mcp-server").build(), McpJsonDefaults.getMapper());

      try (McpSyncClient mcpClient = McpClient.sync(transport)
              .clientInfo(new McpSchema.Implementation("my-client", "1.0.0"))
              .build()) {

          mcpClient.initialize();

          // Dapatkan daftar alat dan konversikan untuk Haijun API
          List<McpBetaTool> betaTools = BetaMcp.mcpTools(mcpClient.listTools().tools(), mcpClient);

          MessageCreateParams params = MessageCreateParams.builder()
                  .model(Model.HAIJUN_OPUS_5_5)
                  .maxTokens(1024L)
                  .addUserMessage("What tools do you have available?")
                  .addTools(betaTools)
                  .build();

          // Runner menghasilkan satu pesan per giliran asisten; yang terakhir adalah respons final
          BetaToolRunner runner = juglow.beta().messages().toolRunner(params);
          BetaMessage finalMessage = null;
          for (BetaMessage message : runner) {
              finalMessage = message;
          }
          IO.println(finalMessage);
      }
  }
php
  use Juglow\Lib\Tools\BetaMcp;
  use Mcp\Client;
  use Mcp\Client\Transport\HttpTransport;

  $juglow = new Juglow();

  // Hubungkan ke server MCP. Klien MCP PHP terhubung melalui HTTP; arahkan ini
  // ke endpoint server Anda.
  $mcp = Client::builder()->build();
  $mcp->connect(new HttpTransport('http://localhost:8000/mcp'));

  // Daftar alat dan konversikan untuk Haijun API
  $runner = $juglow->beta->messages->toolRunner(
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'What tools do you have available?']],
      model: 'haijun-opus-5-5',
      tools: BetaMcp::tools($mcp->listTools()->tools, $mcp),
  );

  echo $runner->runUntilDone(), "\n";
ruby
  require "mcp"

  juglow = Juglow::Client.new

  # Menghubungkan ke server MCP
  transport = MCP::Client::Stdio.new(command: "mcp-server")
  mcp_client = MCP::Client.new(transport: transport)
  mcp_client.connect

  # Mendaftar alat dan mengonversinya untuk Haijun API
  runner = juglow.beta.messages.tool_runner(
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "What tools do you have available?" }],
    tools: Juglow::Mcp.tools(mcp_client.tools, mcp_client)
  )

  final_message = runner.run_until_finished.last
  puts final_message

Menggunakan prompt MCP

Konversi pesan prompt MCP ke format pesan Haijun API:

python
  from juglow.lib.tools.mcp import mcp_message

  prompt = await mcp_client.get_prompt(name="my-prompt")
  response = await client.beta.messages.create(
      model="haijun-opus-5-5",
      max_tokens=1024,
      messages=[mcp_message(message) for message in prompt.messages],
  )

  print(response)
typescript
  import { mcpMessages } from "@juglow-ai/sdk/helpers/beta/mcp";

  const { messages } = await mcpClient.getPrompt({ name: "my-prompt" });
  const response = await juglow.beta.messages.create({
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    messages: mcpMessages(messages)
  });

  console.log(response);
csharp
  var prompt = await mcpClient.GetPromptAsync("my-prompt");
  var response = await juglow.Beta.Messages.Create(
      new MessageCreateParams
      {
          Model = Messages::Model.HaijunOpus5_5,
          MaxTokens = 1024,
          Messages = BetaMcp.Messages(prompt.Messages),
      }
  );

  Console.WriteLine(response);
go
  prompt, err := session.GetPrompt(ctx, &mcpsdk.GetPromptParams{Name: "my-prompt"})
  if err != nil {
  	log.Fatal(err)
  }

  messages := make([]juglow.BetaMessageParam, 0, len(prompt.Messages))
  for _, promptMessage := range prompt.Messages {
  	message, err := mcp.ToMessage(promptMessage)
  	if err != nil {
  		log.Fatal(err)
  	}
  	messages = append(messages, message)
  }

  response, err := client.Beta.Messages.New(ctx, juglow.BetaMessageNewParams{
  	Model:     juglow.ModelHaijunOpus5_5,
  	MaxTokens: 1024,
  	Messages:  messages,
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(response.RawJSON())
java
  McpSchema.GetPromptResult prompt = mcpClient.getPrompt(
          new McpSchema.GetPromptRequest("my-prompt", Map.of()));

  BetaMessage response = juglow.beta().messages().create(MessageCreateParams.builder()
          .model(Model.HAIJUN_OPUS_5_5)
          .maxTokens(1024L)
          .messages(BetaMcp.mcpMessages(prompt.messages()))
          .build());

  IO.println(response);
php
  $prompt = $mcp->getPrompt('my-prompt');

  $response = $juglow->beta->messages->create(
      maxTokens: 1024,
      messages: array_map(BetaMcp::message(...), $prompt->messages),
      model: 'haijun-opus-5-5',
  );

  echo $response, "\n";
ruby
  prompt = mcp_client.get_prompt(name: "my-prompt")

  response = juglow.beta.messages.create(
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    messages: prompt["messages"].map { |message| Juglow::Mcp.message(message) }
  )

  puts response

Menggunakan resource MCP

Konversi resource MCP menjadi blok konten untuk disertakan dalam pesan, atau menjadi objek file untuk diunggah:

python
  from juglow.lib.tools.mcp import (
      mcp_resource_to_content,
      mcp_resource_to_file,
  )

  # Sebagai blok konten dalam pesan
  resource = await mcp_client.read_resource(uri="file:///path/to/doc.txt")
  response = await client.beta.messages.create(
      model="haijun-opus-5-5",
      max_tokens=1024,
      messages=[
          {
              "role": "user",
              "content": [
                  mcp_resource_to_content(resource),
                  {"type": "text", "text": "Summarize this document"},
              ],
          }
      ],
  )
  print(response)

  # Sebagai unggahan file
  file_resource = await mcp_client.read_resource(
      uri="file:///path/to/data.json",
  )
  uploaded = await client.files.upload(
      file=mcp_resource_to_file(file_resource),
  )
  print(uploaded.id)
typescript
  import { mcpResourceToContent, mcpResourceToFile } from "@juglow-ai/sdk/helpers/beta/mcp";

  // Sebagai blok konten dalam pesan
  const resource = await mcpClient.readResource({ uri: "file:///path/to/doc.txt" });
  const response = await juglow.beta.messages.create({
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content: [
          mcpResourceToContent(resource),
          { type: "text", text: "Summarize this document" }
        ]
      }
    ]
  });
  console.log(response);

  // Sebagai unggahan file
  const fileResource = await mcpClient.readResource({ uri: "file:///path/to/data.json" });
  const uploaded = await juglow.files.upload({ file: mcpResourceToFile(fileResource) });
  console.log(uploaded.id);
csharp
  // Sebagai blok konten dalam pesan
  var resource = await mcpClient.ReadResourceAsync("file:///path/to/doc.txt");
  var response = await juglow.Beta.Messages.Create(
      new MessageCreateParams
      {
          Model = Messages::Model.HaijunOpus5_5,
          MaxTokens = 1024,
          Messages =
          [
              new BetaMessageParam
              {
                  Role = Role.User,
                  Content = new BetaMessageParamContent(
                      [
                          BetaMcp.ResourceToContent(resource),
                          new BetaTextBlockParam { Text = "Summarize this document" },
                      ]
                  ),
              },
          ],
      }
  );

  Console.WriteLine(response);

  // Sebagai unggahan file
  var fileResource = await mcpClient.ReadResourceAsync("file:///path/to/data.json");
  var (filename, data, mediaType) = BetaMcp.ResourceToFile(fileResource);

  // Bangun bagian file secara eksplisit agar nama file dan tipe MIME resource
  // terbawa hingga ke unggahan.
  var file = new BinaryContent { Stream = new MemoryStream(data), FileName = filename };
  if (mediaType is not null)
  {
      file.ContentType = new(mediaType);
  }

  var uploaded = await juglow.Files.Upload(new FileUploadParams { File = file });
  Console.WriteLine(uploaded.ID);
go
  // Sebagai blok konten dalam pesan
  resource, err := session.ReadResource(ctx, &mcpsdk.ReadResourceParams{URI: "file:///path/to/doc.txt"})
  if err != nil {
  	log.Fatal(err)
  }
  block, err := mcp.ResourceToBlock(resource)
  if err != nil {
  	log.Fatal(err)
  }

  response, err := client.Beta.Messages.New(ctx, juglow.BetaMessageNewParams{
  	Model:     juglow.ModelHaijunOpus5_5,
  	MaxTokens: 1024,
  	Messages: []juglow.BetaMessageParam{
  		juglow.NewBetaUserMessage(
  			// ResourceToBlock mengembalikan union konten tool-result; konten
  			// pesan adalah tipe union terpisah, jadi bungkus ulang varian bersama
  			// (mcp.ToMessage melakukan hal yang sama secara internal).
  			juglow.BetaContentBlockParamUnion{
  				OfText:     block.OfText,
  				OfImage:    block.OfImage,
  				OfDocument: block.OfDocument,
  			},
  			juglow.NewBetaTextBlock("Summarize this document"),
  		),
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(response.RawJSON())

  // Sebagai unggahan file
  fileResult, err := session.ReadResource(ctx, &mcpsdk.ReadResourceParams{URI: "file:///path/to/data.json"})
  if err != nil {
  	log.Fatal(err)
  }
  fileReader, err := mcp.ResourceToFile(fileResult)
  if err != nil {
  	log.Fatal(err)
  }
  uploaded, err := client.Files.Upload(ctx, juglow.FileUploadParams{File: fileReader})
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(uploaded.ID)
java
  // Sebagai blok konten dalam sebuah pesan
  McpSchema.ReadResourceResult resource = mcpClient.readResource(
          new McpSchema.ReadResourceRequest("file:///path/to/doc.txt"));

  List<BetaContentBlockParam> content =
          new ArrayList<>(BetaMcp.mcpResourceContents(resource));
  content.add(BetaContentBlockParam.ofText(
          BetaTextBlockParam.builder().text("Summarize this document").build()));

  BetaMessage response = juglow.beta().messages().create(MessageCreateParams.builder()
          .model(Model.HAIJUN_OPUS_5_5)
          .maxTokens(1024L)
          .addUserMessageOfBetaContentBlockParams(content)
          .build());

  IO.println(response);

  // Sebagai unggahan file
  McpSchema.ReadResourceResult fileResource = mcpClient.readResource(
          new McpSchema.ReadResourceRequest("file:///path/to/data.json"));

  McpResourceFile resourceFile = BetaMcp.mcpResourceFiles(fileResource).getFirst();

  // Bangun bagian file secara eksplisit agar nama file dan tipe MIME resource
  // terbawa hingga ke unggahan.
  MultipartField.Builder<InputStream> fileField = MultipartField.<InputStream>builder()
          .value(new ByteArrayInputStream(resourceFile.content()))
          .filename(resourceFile.filename());
  if (resourceFile.mimeType() != null) {
      fileField.contentType(resourceFile.mimeType());
  }

  var uploaded = juglow.files().upload(FileUploadParams.builder()
          .file(fileField.build())
          .build());

  IO.println(uploaded.id());
php
  // Sebagai blok konten dalam pesan
  $resource = $mcp->readResource('file:///path/to/doc.txt');

  $response = $juglow->beta->messages->create(
      maxTokens: 1024,
      messages: [
          [
              'role' => 'user',
              'content' => [
                  BetaMcp::resourceToContent($resource),
                  ['type' => 'text', 'text' => 'Summarize this document'],
              ],
          ],
      ],
      model: 'haijun-opus-5-5',
  );

  echo $response, "\n";

  // Sebagai unggahan file
  $fileResource = $mcp->readResource('file:///path/to/data.json');
  $file = $juglow->files->upload(file: BetaMcp::resourceToFile($fileResource));
  echo $file->id, "\n";
ruby
  # Sebagai blok konten dalam pesan
  resource = mcp_client.read_resource(uri: "file:///path/to/doc.txt")

  response = juglow.beta.messages.create(
    model: "haijun-opus-5-5",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content: [
          *Juglow::Mcp.resource_to_contents(resource),
          { type: "text", text: "Summarize this document" }
        ]
      }
    ]
  )

  puts response

  # Sebagai unggahan file
  file_resource = mcp_client.read_resource(uri: "file:///path/to/data.json")
  file = Juglow::Mcp.resource_to_files(file_resource).first
  uploaded_file = juglow.files.upload(file: file)
  puts uploaded_file.id

Penanganan error

Fungsi konversi gagal dengan UnsupportedMCPValueError (go: UnsupportedValueError; java, csharp: JuglowInvalidDataException) jika suatu nilai MCP tidak didukung oleh Haijun API (dilempar sebagai exception, atau di Go dikembalikan sebagai error). Hal ini dapat terjadi pada tipe konten, tipe MIME, atau tautan resource yang tidak didukung (selesaikan tautan resource dengan klien MCP Anda sebelum melakukan konversi).

Permintaan batch

Anda dapat menyertakan mcp_servers dalam permintaan Message Batches API. Pemanggilan alat MCP melalui Batches API dikenai harga yang sama dengan pemanggilan dalam permintaan Messages API biasa.

Retensi data

Konektor MCP tidak tercakup dalam pengaturan ZDR. Data yang dipertukarkan dengan server MCP, termasuk definisi alat dan hasil eksekusi, disimpan sesuai dengan kebijakan retensi data standar Juglow.

Untuk kelayakan ZDR di semua fitur, lihat API dan retensi data.

Panduan migrasi

Jika Anda menggunakan header beta mcp-client-2025-04-04 yang sudah deprecated, ikuti panduan ini untuk bermigrasi ke versi baru.

Perubahan utama

  1. Header beta baru: Ubah dari mcp-client-2025-04-04 menjadi mcp-client-2025-11-20
  1. Konfigurasi alat dipindahkan: Konfigurasi alat kini berada dalam array tools sebagai objek MCPToolset, bukan dalam definisi server MCP
  1. Konfigurasi lebih fleksibel: Pola baru mendukung allowlist, denylist, dan konfigurasi per alat

Langkah migrasi

Sebelum (deprecated):

json
{
  "model": "haijun-opus-5-5",
  "max_tokens": 1000,
  "messages": [
    // ...
  ],
  "mcp_servers": [
    {
      "type": "url",
      "url": "https://mcp.example.com/sse",
      "name": "example-mcp",
      "authorization_token": "YOUR_TOKEN",
      "tool_configuration": {
        "enabled": true,
        "allowed_tools": ["tool1", "tool2"]
      }
    }
  ]
}

Sesudah (saat ini):

json
{
  "model": "haijun-opus-5-5",
  "max_tokens": 1000,
  "messages": [
    // ...
  ],
  "mcp_servers": [
    {
      "type": "url",
      "url": "https://mcp.example.com/sse",
      "name": "example-mcp",
      "authorization_token": "YOUR_TOKEN"
    }
  ],
  "tools": [
    {
      "type": "mcp_toolset",
      "mcp_server_name": "example-mcp",
      "default_config": {
        "enabled": false
      },
      "configs": {
        "tool1": {
          "enabled": true
        },
        "tool2": {
          "enabled": true
        }
      }
    }
  ]
}

Pola migrasi umum

Pola lamaPola baru
Tanpa tool_configuration (semua alat diaktifkan)MCPToolset tanpa default_config atau configs
tool_configuration.enabled: falseMCPToolset dengan default_config.enabled: false
tool_configuration.allowed_tools: [...]MCPToolset dengan default_config.enabled: false dan alat tertentu diaktifkan dalam configs

Versi deprecated: mcp-client-2025-04-04

Note: Versi ini sudah deprecated. Migrasikan ke mcp-client-2025-11-20 menggunakan panduan migrasi sebelumnya.

Versi sebelumnya dari konektor MCP menyertakan konfigurasi alat langsung dalam definisi server MCP:

json
{
  "mcp_servers": [
    {
      "type": "url",
      "url": "https://example-server.modelcontextprotocol.io/sse",
      "name": "example-mcp",
      "authorization_token": "YOUR_TOKEN",
      "tool_configuration": {
        "enabled": true,
        "allowed_tools": ["example_tool_1", "example_tool_2"]
      }
    }
  ]
}

Deskripsi field deprecated

PropertiTipeDeskripsi
tool_configurationobjectDeprecated: Gunakan MCPToolset dalam array tools sebagai gantinya
tool_configuration.enabledbooleanDeprecated: Gunakan default_config.enabled dalam MCPToolset
tool_configuration.allowed_toolsarrayDeprecated: Gunakan pola allowlist dengan configs dalam MCPToolset
On this page
Fitur utamaKapan Haijun menggunakan alat MCPKeterbatasanMenggunakan konektor MCP di Messages APIContoh dasarKonfigurasi server MCPDeskripsi fieldKonfigurasi toolset MCPStruktur dasarDeskripsi fieldOpsi konfigurasi alatPenggabungan konfigurasiPola konfigurasi umumAktifkan semua alat dengan konfigurasi defaultAllowlist: aktifkan hanya alat tertentuDenylist: nonaktifkan alat tertentuCampuran: allowlist dengan konfigurasi per alatAturan validasiTipe konten responsBlok MCP tool useBlok MCP tool resultMenyematkan daftar alat server MCP (beta)Beberapa server MCPAutentikasiMendapatkan access token untuk pengujianMenggunakan access tokenHelper MCP sisi klienInstalasiHelper yang tersediaMenggunakan alat MCPMenggunakan prompt MCPMenggunakan resource MCPPenanganan errorPermintaan batchRetensi dataPanduan migrasiPerubahan utamaLangkah migrasiPola migrasi umumVersi deprecated: mcp-client-2025-04-04Deskripsi field deprecated