대화에서 커넥터 사용하기

대화에서 커넥터 사용하기 (Using Connectors in Conversations)

Mistral AI 대화에서 Connectors, 내장 도구, 에이전트를 사용하는 방법을 다루는 레퍼런스 쿡북이에요. 총 8개의 레시피로, 기본 대화부터 커스텀 커넥터, OAuth 인증 커넥터, 전체 수명주기 예제까지 다양하게 다뤄요.

출처: 문서

본문

Mistral AI 대화에서 Connectors, 내장 도구(built-in tools), **에이전트(agents)**를 사용해 봅시다.

API 상태 (API status): Conversations는 client.beta.conversations를, Agents는 client.beta.agents를 사용해요. 이들은 베타(beta) 엔드포인트로 변경될 수 있어요.

사전 준비사항 (Prerequisites)

설치 (Install)

# Python
pip install mistralai
# or with uv
uv add mistralai
# TypeScript
pnpm add @mistralai/mistralai

필요한 환경 변수 (Required environment variables)

이 쿡북을 완료하려면 Mistral API 키가 필요해요. Studio에서 API keys 섹션으로 이동해서 새 API 키를 만들어요.

프로젝트 루트에 .env를 만들고 Mistral API 키를 추가해요.

MISTRAL_API_KEY=your-mistral-api-key

시작 전에 필요한 것 (What you need before starting)

대부분의 레시피는 이미 다음이 있다고 가정해요.

  • 작동하는 client (Recipe 1 참조)
  • 커스텀 커넥터 레시피를 위한 기존 커넥터 — Build a Database Advisor Agent를 보면 전체 커넥터 수명주기 예제를 볼 수 있고, Studio에서 만들 수도 있어요.

대화 응답 읽기 (Reading Conversation Responses)

이 쿡북의 모든 레시피는 모델의 텍스트 출력을 인쇄하는 작은 display_response 헬퍼를 사용해요. Conversations API는 outputs 목록을 반환하고, type == "message.output"인 각 출력이 모델의 답변을 담아요. 콘텐츠는 일반 문자열이거나 콘텐츠 청크 목록일 수 있어요.

Python:

def display_response(response) -> None:
    for output in response.outputs:
        if output.type == "message.output":
            content = output.content
            if isinstance(content, str):
                print(content)
            else:
                text = "".join(
                    chunk.text if hasattr(chunk, "text") else str(chunk)
                    for chunk in content
                )
                print(text)

TypeScript:

function displayResponse(response: any): void {
  for (const output of response.outputs ?? []) {
    if (output.type === "message.output") {
      const content = output.content;
      if (typeof content === "string") {
        console.log(content);
      } else if (Array.isArray(content)) {
        const text = content
          .map((chunk: any) => chunk.text ?? String(chunk))
          .join("");
        console.log(text);
      }
    }
  }
}

아래의 모든 레시피는 이 헬퍼를 참조해요. 프로젝트에 복사하거나 로직을 인라인해도 돼요.

레시피 (Recipes)

1. Hello world — 첫 대화 (first conversation)

목표 (Goal): 도구나 커넥터 없이 첫 메시지를 보내고 응답을 읽어 보아요.

언제 쓰나 (When to use):

  • 설정이 끝에서 끝까지(end-to-end) 작동하는지 확인할 때
  • 커넥터를 추가하기 전에 응답 구조에 익숙해질 때

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    response = await client.beta.conversations.start_async(
        model="mistral-small-latest",
        inputs=[
            {"role": "user", "content": "What is the capital of France?"}
        ],
    )
    display_response(response)

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  const response = await client.beta.conversations.start({
    model: "mistral-small-latest",
    inputs: [
      { role: "user", content: "What is the capital of France?" },
    ],
  });
  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "inputs": [{"role": "user", "content": "What is the capital of France?"}]
  }'

출력 예시 (Example of output):

The capital of France is Paris.

작동 방식 (How it works):

  • conversations.start/start_async는 무상태(stateless) 대화 턴을 모델에 보내요.
  • 응답에는 outputs 목록이 포함되고, 각각의 type == "message.output"가 모델의 답변을 담아요.
  • 기본 대화에는 도구나 커넥터가 필요 없어요.

일반적인 오류와 해결책 (Common errors & fixes):

Error Cause Fix
401 Unauthorized Bad API key Check MISTRAL_API_KEY
422 Unprocessable Entity Invalid model name Use a valid model like mistral-small-latest

목표 (Goal): 커스텀 커넥터 없이 모델에 실시간 웹 정보 접근권을 주어요.

언제 쓰나 (When to use):

  • 사용자의 질문에 최신 정보(날씨, 뉴스, 현재 이벤트)가 필요할 때
  • 커넥터를 만들거나 관리하지 않고 빠르게 통합하고 싶을 때

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    response = await client.beta.conversations.start_async(
        model="mistral-small-latest",
        inputs=[
            {
                "role": "user",
                "content": "What is the current weather in Paris? Use web search.",
            }
        ],
        tools=[
            {"type": "web_search"},
        ],
    )
    display_response(response)

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  const response = await client.beta.conversations.start({
    model: "mistral-small-latest",
    inputs: [
      {
        role: "user",
        content: "What is the current weather in Paris? Use web search.",
      },
    ],
    tools: [
      { type: "web_search" },
    ],
  });
  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "inputs": [{"role": "user", "content": "What is the current weather in Paris?"}],
    "tools": [{"type": "web_search"}]
  }'

출력 예시 (Example of output):

Based on current web search results, the weather in Paris today is 8°C with partly cloudy skies...

작동 방식 (How it works):

  • web_search는 내장 도구 유형이라 커넥터 생성이 필요 없어요.
  • 모델이 쿼리에 따라 검색을 호출할지 자율적으로 결정해요.
  • 검색 결과가 모델의 응답에 자동으로 포함돼요.

일반적인 오류와 해결책 (Common errors & fixes):

Error Cause Fix
422 Unprocessable Entity Invalid tool type Ensure the type is exactly "web_search"

3. 커스텀 커넥터를 사용한 대화 (Conversation with a custom connector)

목표 (Goal): 대화에서 Connector를 사용해서 모델이 외부 도구를 호출하게 해요.

언제 쓰나 (When to use):

  • 커넥터(예: DeepWiki)를 등록했고 모델이 그 도구를 사용하길 원할 때
  • 도메인별 기능(코드 검색, 문서 조회, 액션 등)을 모델에 연결할 때

사전 준비사항 (Prereqs):

기존 커넥터 — Build a Database Advisor Agent를 보면 전체 커넥터 수명주기 예제를 볼 수 있고, Studio에서 만들 수도 있어요.

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    response = await client.beta.conversations.start_async(
        model="mistral-small-latest",
        inputs=[
            {
                "role": "user",
                "content": "Using deepwiki, tell me about the structure of the sqlite/sqlite repository.",
            }
        ],
        tools=[
            {
                "type": "connector",
                "connector_id": "my_deepwiki",  # name or UUID
            },
        ],
    )
    display_response(response)

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  const response = await client.beta.conversations.start({
    model: "mistral-small-latest",
    inputs: [
      {
        role: "user",
        content:
          "Using deepwiki, tell me about the structure of the sqlite/sqlite repository.",
      },
    ],
    tools: [
      {
        type: "connector",
        connectorId: "my_deepwiki", // name or UUID
      },
    ],
  });
  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "inputs": [{"role": "user", "content": "Using deepwiki, tell me about the structure of the sqlite/sqlite repository."}],
    "tools": [{"type": "connector", "connector_id": "my_deepwiki"}]
  }'

출력 예시 (Example of output):

The sqlite/sqlite repository is organized into several key directories:
- src/ — core SQLite source code
- ext/ — extensions
- test/ — test suite
...

작동 방식 (How it works):

  • connector_id 필드는 커넥터의 name 또는 UUID를 받아요.
  • 모델이 MCP 서버가 노출하는 도구를 발견하고 호출할 것을 결정해요.
  • 도구 호출과 결과는 서버 쪽에서 처리되어, 최종 응답만 보여요.

일반적인 오류와 해결책 (Common errors & fixes):

Error Cause Fix
404 Not Found (or graceful fallback) Connector name/ID doesn't exist — the API may return a 404 or handle gracefully Verify with client.beta.connectors.get
422 Unprocessable Entity Connector is inactive or MCP server unreachable Check the MCP server URL

4. 하나의 대화에서 여러 도구 결합 (Combining multiple tools in one conversation)

목표 (Goal): 모델에게 웹 검색 그리고 커스텀 커넥터를 동시에 접근하게 해요.

언제 쓰나 (When to use):

  • 모델이 여러 옵션 중 작업에 가장 좋은 도구를 선택하길 원할 때
  • 다중 기능 어시스턴트(예: 웹 검색 + 내부 문서 쿼리)를 구축할 때

사전 준비사항 (Prereqs):

기존 커넥터.

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    response = await client.beta.conversations.start_async(
        model="mistral-small-latest",
        inputs=[
            {
                "role": "user",
                "content": "What tools do you have access to? List them briefly.",
            }
        ],
        tools=[
            {"type": "web_search"},
            {
                "type": "connector",
                "connector_id": "my_deepwiki",
            },
        ],
    )
    display_response(response)

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  const response = await client.beta.conversations.start({
    model: "mistral-small-latest",
    inputs: [
      {
        role: "user",
        content: "What tools do you have access to? List them briefly.",
      },
    ],
    tools: [
      { type: "web_search" },
      {
        type: "connector",
        connectorId: "my_deepwiki",
      },
    ],
  });
  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "inputs": [{"role": "user", "content": "What tools do you have access to? List them briefly."}],
    "tools": [
      {"type": "web_search"},
      {"type": "connector", "connector_id": "my_deepwiki"}
    ]
  }'

출력 예시 (Example of output):

I have access to the following tools:
1. Web Search — search the internet for real-time information
2. read_wiki_structure — explore repository wiki structure
3. read_wiki_contents — read specific wiki pages
4. ask_question — ask questions about a repository

작동 방식 (How it works):

  • tools 배열은 내장 도구(web_search)와 커스텀 커넥터를 어떤 조합으로든 받아요.
  • 각 커넥터는 자체 MCP 도구 세트를 노출하고, 모델은 그 모두를 봐요.
  • 모델이 사용자 질문에 따라 호출할 도구를 결정해요.

일반적인 오류와 해결책 (Common errors & fixes):

Error Cause Fix
422 Unprocessable Entity Duplicate connector IDs in the tools array Each connector should appear only once

5. 커넥터 도구 필터링 — include / exclude

목표 (Goal): 커넥터에서 어떤 MCP 도구를 모델에 보이게 할지 제어해요.

언제 쓰나 (When to use):

  • 커넥터가 많은 도구를 노출하지만 일부만 필요할 때
  • 모델이 특정 도구(예: 쓰기/삭제 연산)를 호출하지 못하게 하고 싶을 때
  • 도구 노이즈를 줄여서 모델 정확도를 높이고 싶을 때

사전 준비사항 (Prereqs):

기존 커넥터와 그것이 노출하는 도구 이름에 대한 지식.

참고 (Note): include 또는 exclude 중 하나만 사용하세요. 둘을 동시에 쓰면 안 됩니다.

특정 도구 제외 (Excluding specific tools)

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    response = await client.beta.conversations.start_async(
        model="mistral-small-latest",
        inputs=[
            {
                "role": "user",
                "content": "What tools do you have access to? List their names.",
            }
        ],
        tools=[
            {
                "type": "connector",
                "connector_id": "my_deepwiki",
                "tool_configuration": {
                    "exclude": ["read_wiki_structure"],
                },
            },
        ],
    )
    display_response(response)

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  const response = await client.beta.conversations.start({
    model: "mistral-small-latest",
    inputs: [
      {
        role: "user",
        content: "What tools do you have access to? List their names.",
      },
    ],
    tools: [
      {
        type: "connector",
        connectorId: "my_deepwiki",
        toolConfiguration: {
          exclude: ["read_wiki_structure"],
        },
      },
    ],
  });
  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "inputs": [{"role": "user", "content": "What tools do you have access to?"}],
    "tools": [{
      "type": "connector",
      "connector_id": "my_deepwiki",
      "tool_configuration": { "exclude": ["read_wiki_structure"] }
    }]
  }'

출력 (Output):

I have access to: read_wiki_contents, ask_question

특정 도구만 포함 (Including only specific tools)

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    response = await client.beta.conversations.start_async(
        model="mistral-small-latest",
        inputs=[
            {
                "role": "user",
                "content": "What tools do you have access to? List their names.",
            }
        ],
        tools=[
            {
                "type": "connector",
                "connector_id": "my_deepwiki",
                "tool_configuration": {
                    "include": ["ask_question"],
                },
            },
        ],
    )
    display_response(response)

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  const response = await client.beta.conversations.start({
    model: "mistral-small-latest",
    inputs: [
      {
        role: "user",
        content: "What tools do you have access to? List their names.",
      },
    ],
    tools: [
      {
        type: "connector",
        connectorId: "my_deepwiki",
        toolConfiguration: {
          include: ["ask_question"],
        },
      },
    ],
  });
  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "inputs": [{"role": "user", "content": "What tools do you have access to?"}],
    "tools": [{
      "type": "connector",
      "connector_id": "my_deepwiki",
      "tool_configuration": { "include": ["ask_question"] }
    }]
  }'

출력 예시 (Example of output):

I have access to: ask_question

작동 방식 (How it works):

  • tool_configuration.exclude는 나열된 도구를 커넥터에서 제거해요. 다른 도구는 모두 사용 가능하게 남아요.
  • tool_configuration.include는 나열된 도구를 허용 목록에 넣어요. 다른 도구는 모두 숨겨져요.
  • 도구 이름은 MCP 서버가 노출하는 것과 정확히 일치해야 해요. 먼저 모델에게 (필터 없이) 도구 목록을 요청해서 정확한 이름을 발견하세요.

일반적인 오류와 해결책 (Common errors & fixes):

Error Cause Fix
422 Unprocessable Entity Tool name doesn't match any tool on the MCP server List all tools first to get exact names
400 Bad Request Both include and exclude provided Use only one at a time

6. 커넥터로 에이전트 만들기 (Creating an agent with connectors)

목표 (Goal): 커넥터와 커스텀 지시사항이 미리 구성된 영구 에이전트를 만든 다음, 그것과 대화해요.

언제 쓰나 (When to use):

  • 항상 특정 도구에 접근해야 하는 재사용 가능한 에이전트를 원할 때 — 매 호출에 tools 배열을 전달할 필요 없어요.
  • 사용자가 전문화된 어시스턴트와 상호작용하는 제품 기능을 구축할 때

사전 준비사항 (Prereqs):

기존 커넥터.

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    agent_id: str | None = None
    try:
        # 1. Create the agent
        agent = await client.beta.agents.create_async(
            name="deepwiki_agent",
            description="Agent with DeepWiki access for code repository exploration",
            model="mistral-small-latest",
            instructions="You are a helpful assistant that can explore code repositories using DeepWiki. Be concise.",
            tools=[
                {
                    "type": "connector",
                    "connector_id": "my_deepwiki",
                },
            ],
        )
        agent_id = agent.id
        print(f"Created agent: {agent.name} ({agent.id})")

        # 2. Start a conversation using the agent
        response = await client.beta.conversations.start_async(
            agent_id=agent.id,
            inputs=[
                {
                    "role": "user",
                    "content": "What is the main purpose of the sqlite repository?",
                }
            ],
        )
        display_response(response)

    finally:
        # 3. Cleanup
        if agent_id:
            await client.beta.agents.delete_async(agent_id=agent_id)
            print(f"Deleted agent: {agent_id}")

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  let agentId: string | undefined;
  try {
    // 1. Create the agent
    const agent = await client.beta.agents.create({
      name: "deepwiki_agent",
      description: "Agent with DeepWiki access for code repository exploration",
      model: "mistral-small-latest",
      instructions:
        "You are a helpful assistant that can explore code repositories using DeepWiki. Be concise.",
      tools: [
        {
          type: "connector",
          connectorId: "my_deepwiki",
        },
      ],
    });
    agentId = agent.id;
    console.log(`Created agent: ${agent.name} (${agent.id})`);

    // 2. Start a conversation using the agent
    const response = await client.beta.conversations.start({
      agentId: agent.id,
      inputs: [
        {
          role: "user",
          content: "What is the main purpose of the sqlite repository?",
        },
      ],
    });
    displayResponse(response);
  } finally {
    // 3. Cleanup
    if (agentId) {
      await client.beta.agents.delete({ agentId });
      console.log(`Deleted agent: ${agentId}`);
    }
  }
}

main();

curl:

# Create agent
curl -X POST "https://api.mistral.ai/v1/agents" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "deepwiki_agent",
    "description": "Agent with DeepWiki access",
    "model": "mistral-small-latest",
    "instructions": "You are a helpful assistant that can explore code repositories using DeepWiki. Be concise.",
    "tools": [{"type": "connector", "connector_id": "my_deepwiki"}]
  }'

# Start conversation with agent (use the agent ID from the response above)
curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "<agent-id>",
    "inputs": [{"role": "user", "content": "What is the main purpose of the sqlite repository?"}]
  }'

# Delete agent when done
curl -X DELETE "https://api.mistral.ai/v1/agents/<agent-id>" \
  -H "Authorization: Bearer ${MIST...KEY}"

출력 예시 (Example of output):

Created agent: deepwiki_agent (b2c3d4e5-6789-01ab-cdef-234567890abc)
SQLite is a self-contained, serverless, zero-configuration SQL database engine...
Deleted agent: b2c3d4e5-6789-01ab-cdef-234567890abc

작동 방식 (How it works):

  • 에이전트는 영구 구성이에요: model + instructions + tools.
  • agent_id로 대화를 시작하면 모델, 지시사항, 도구가 미리 로드되어 다시 전달할 필요 없어요.
  • 에이전트의 tools 배열은 대화의 tools 매개변수와 동일한 형식을 사용해요.
  • 대화를 시작할 때 model 대신 agent_id를 사용하세요 — 둘을 함께 쓰면 안 됩니다.
  • 더 이상 필요 없을 때는 client.beta.agents.delete / delete_async로 에이전트를 삭제해요.

일반적인 오류와 해결책 (Common errors & fixes):

Error Cause Fix
404 Not Found The connector referenced in the agent's tools doesn't exist Create the connector first
422 Unprocessable Entity Both model and agent_id provided, or invalid tool format Use only agent_id when chatting with an agent

7. OAuth 인증 커넥터 (Gmail) (OAuth-authenticated connectors)

목표 (Goal): Gmail처럼 OAuth2 인증이 필요한 커넥터를 사용해요.

언제 쓰나 (When to use):

  • Gmail, Google Drive, Slack처럼 사용자 수준의 OAuth 토큰이 필요한 서비스와 통합할 때
  • 모델이 사용자별 데이터에 접근하는 기능을 구축할 때

사전 준비사항 (Prereqs):

대상 서비스에 대한 유효한 OAuth2 액세스 토큰.

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    google_oauth_token = "your-google-oauth-token"

    response = await client.beta.conversations.start_async(
        model="mistral-small-latest",
        inputs=[
            {
                "role": "user",
                "content": "What's the latest email I received?",
            }
        ],
        tools=[
            {
                "type": "connector",
                "connector_id": "gmail",
                "authorization": {
                    "type": "oauth2-token",
                    "value": google_oauth_token,
                },
            },
        ],
    )
    display_response(response)

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  const googleOauthToken = "your-google-oauth-token";

  const response = await client.beta.conversations.start({
    model: "mistral-small-latest",
    inputs: [
      {
        role: "user",
        content: "What's the latest email I received?",
      },
    ],
    tools: [
      {
        type: "connector",
        connectorId: "gmail",
        authorization: ***
          type: "oauth2-token",
          value: googleOauthToken,
        },
      },
    ],
  });
  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/conversations" \
  -H "Authorization: Bearer ${MIST...KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "inputs": [{"role": "user", "content": "What is the latest email I received?"}],
    "tools": [{
      "type": "connector",
      "connector_id": "gmail",
      "authorization": {
        "type": "oauth2-token",
        "value": "<your-google-oauth-token>"
      }
    }]
  }'

출력 예시 (Example of output):

Your latest email is from John Doe with the subject "Q1 Report Review" received at 2:30 PM today...

작동 방식 (How it works):

  • authorization 필드는 전역이 아니라 도구별로(per-tool) 전달돼요 — 서로 다른 커넥터가 서로 다른 토큰을 사용할 수 있어요.
  • type: "oauth2-token"은 백엔드에게 토큰을 MCP 서버로 전달하라고 알려줘요.
  • 토큰은 Mistral이 저장하지 않아요 — 요청 기간 동안만 사용돼요.
  • gmail 같은 내장 커넥터는 미리 등록되어 있어 직접 만들 필요 없어요.

일반적인 오류와 해결책 (Common errors & fixes):

Error Cause Fix
401 Unauthorized OAuth token is expired Refresh the token and retry
403 Forbidden Token doesn't have required scopes Request the correct scopes (e.g., gmail.readonly)

8. 전체 예제 — 커넥터 만들고, 대화하고, 정리하기 (Full example — create a connector, chat, and clean up)

목표 (Goal): 커넥터를 만들고 대화에서 사용한 뒤 정리하는 끝에서 끝까지(end-to-end) 워크플로우.

언제 쓰나 (When to use):

  • 통합 테스트
  • 일회성 작업을 위한 임시(ephemeral) 커넥터
  • 프로덕션 워크플로우 템플릿

Python:

import asyncio
from mistralai import Mistral

client = Mistral(api_key="your-api-key")

async def main() -> None:
    connector_id: str | None = None

    try:
        # 1. Create a connector
        connector = await client.beta.connectors.create_async(
            name="ephemeral_deepwiki",
            description="Temporary connector for a one-off task",
            server="https://mcp.deepwiki.com/mcp",
            visibility="private",
        )
        connector_id = str(connector.id)
        print(f"Created connector: {connector.name} ({connector.id})")

        # 2. Use it in a simple conversation
        response = await client.beta.conversations.start_async(
            model="mistral-small-latest",
            inputs=[
                {
                    "role": "user",
                    "content": "Using deepwiki, summarize the sqlite/sqlite repo in one sentence.",
                }
            ],
            tools=[
                {"type": "connector", "connector_id": "ephemeral_deepwiki"},
            ],
        )
        print("\nConversation response:")
        display_response(response)

        # 3. Use it alongside web search
        response = await client.beta.conversations.start_async(
            model="mistral-small-latest",
            inputs=[
                {
                    "role": "user",
                    "content": "Search the web for the latest SQLite release version, then use deepwiki to find where the version number is defined in the sqlite/sqlite repo.",
                }
            ],
            tools=[
                {"type": "web_search"},
                {"type": "connector", "connector_id": "ephemeral_deepwiki"},
            ],
        )
        print("\nMulti-tool response:")
        display_response(response)

    finally:
        # 4. Always clean up
        if connector_id:
            result = await client.beta.connectors.delete_async(
                connector_id=connector_id,
            )
            print(f"\nCleaned up connector: {result.message}")

asyncio.run(main())

TypeScript:

import Mistral from "@mistralai/mistralai";

const client = new Mistral({ apiKey: *** });

async function main(): Promise<void> {
  let connectorId: string | undefined;

  try {
    // 1. Create a connector
    const connector = await client.beta.connectors.create({
      name: "ephemeral_deepwiki",
      description: "Temporary connector for a one-off task",
      server: "https://mcp.deepwiki.com/mcp",
      visibility: "private",
    });
    connectorId = connector.id;
    console.log(`Created connector: ${connector.name} (${connector.id})`);

    // 2. Use it in a simple conversation
    const response = await client.beta.conversations.start({
      model: "mistral-small-latest",
      inputs: [
        {
          role: "user",
          content:
            "Using deepwiki, summarize the sqlite/sqlite repo in one sentence.",
        },
      ],
      tools: [
        { type: "connector", connectorId: "ephemeral_deepwiki" },
      ],
    });
    console.log("\nConversation response:");
    displayResponse(response);

    // 3. Use it alongside web search
    const multiResponse = await client.beta.conversations.start({
      model: "mistral-small-latest",
      inputs: [
        {
          role: "user",
          content:
            "Search the web for the latest SQLite release version, then use deepwiki to find where the version number is defined in the sqlite/sqlite repo.",
        },
      ],
      tools: [
        { type: "web_search" },
        { type: "connector", connectorId: "ephemeral_deepwiki" },
      ],
    });
    console.log("\nMulti-tool response:");
    displayResponse(multiResponse);
  } finally {
    // 4. Always clean up
    if (connectorId) {
      const result = await client.beta.connectors.delete({ connectorId });
      console.log(`\nCleaned up connector: ${result.message}`);
    }
  }
}

main();

출력 (Output):

Created connector: ephemeral_deepwiki (c3d4e5f6-...)

Conversation response:
SQLite is a self-contained, serverless SQL database engine used worldwide.

Multi-tool response:
The latest SQLite release is 3.45.1. The version number is defined in src/sqlite.h...

Cleaned up connector: Connector deleted successfully

작동 방식 (How it works):

  • try/finally 패턴은 대화가 실패해도 커넥터가 항상 삭제되도록 보장해요.
  • 이 레시피는 커넥터 CRUD(전체 내용은 Build a Database Advisor Agent 참조)와 대화 사용을 결합해요.
  • 두 번째 대화는 단일 요청 안에서 모델이 웹 검색과 커스텀 커넥터 사이를 지능적으로 라우팅하는 모습을 보여줘요.

요약 (Summary)

이 쿡북은 Mistral AI 대화에서 Connectors, 내장 도구, 에이전트를 사용하는 8가지 레시피를 다뤘어요. 기본 hello world부터 OAuth 인증 커넥터, 전체 create-chat-cleanup 수명주기 예제까지요.

이 쿡북이 다루는 내용 (What this cookbook covers):

  • Conversations API로 대화 시작하기
  • 대화에 웹 검색 추가하기
  • 대화에서 커스텀 Connector 사용하기
  • 하나의 대화에서 여러 도구 결합하기
  • Connector가 노출하는 도구 필터링하기
  • Connectors로 에이전트 만들기
  • OAuth 인증 커넥터(Gmail)
  • 전체 수명주기: Connector 만들고, 대화에서 사용하고, 정리하기

사용한 Mistral 기능 (Mistral features used):

  • Conversations API (beta)
  • Agents API (beta)
  • Connectors (beta)
  • Web search 내장 도구

기타 서비스 (Other services):

  • DeepWiki — GitHub 저장소 탐색용 MCP 서버
  • Gmail — OAuth2 인증 Connector

Connector를 Studio에서 확인할 수 있어요.

더 알아보기 (Learn more)