참고
이는 진화하는 기능입니다. 진행 중인 토론은 문제 #36 을 참조하세요.
MCP란?
MCP(모델 컨텍스트 프로토콜) 는 AI 도우미를 외부 도구 및 데이터 원본에 연결하기 위한 개방형 표준입니다. MCP 서버는 다음을 수행할 수 있습니다.
- 코드 또는 스크립트 실행
- 데이터베이스 쿼리
- 파일 시스템에 액세스
- 외부 API 호출
- 그리고 훨씬 더
서버 유형
SDK는 두 가지 유형의 MCP 서버를 지원합니다.
| Type | Description | 사용 사례 |
|---|---|---|
| Local/Stdio | 하위 프로세스로 실행되며 stdin/stdout을 통해 통신합니다. | 로컬 도구, 파일 액세스, 사용자 지정 스크립트 |
| HTTP/SSE | HTTP를 통해 액세스된 원격 서버 | 공유 서비스, 클라우드 호스팅 도구 |
Configuration
구성 및 수명 주기 검사
session.rpc.mcp.listConfigured() 는 매개 변수가 없는 수동 인벤토리 읽기입니다.
서버를 시작하거나 다시 시작하거나, 인증하거나, 샌드박스 정책을 적용하거나, 서버 시작을 기다리지 않습니다. 구성 검색 및 정책 필터링은 어떤 서버와 그 enabled 값이 표시될지를 결정합니다.
이 실험적 RPC에는 호환되는 SDK/런타임 릴리스가 필요합니다. 이전 시험판 응답에서는 live를 생략할 수 있었습니다. 필요한 수명 주기 계약을 사용하는 SDK는 이전 응답 셰이프를 지원하지 않습니다. 외부 런타임을 제공할 때 SDK와 함께 해당 런타임도 업데이트하세요. 전체 프로토콜 버전은 변경되지 않으며 이 실험적 계약 개정을 식별하지 않습니다.
모든 항목에는 live.status가 포함됩니다. 구체화된 런타임 서버가 없는 구성된 서버는 not_configured이 enabled인 경우에도 기존 true 상태를 보고합니다. 명시적으로 중지된 런타임 서버는 stopped를 보고합니다. 구체화된 서버는 pending, failed, connected, needs-auth를 포함한 실제 수명 주기를 보고하며, 실패에는 가능한 경우 live.error가 포함됩니다.
구성 및 수명 주기는 서로 다른 사실을 설명합니다. 이전 연결이 활성 상태로 유지되는 동안 서버의 URL, 인증 또는 구성 원본이 변경되는 경우 인벤토리는 연결의 실제 수명 주기를 보고합니다.
connected 상태가 최신 구성이 적용되었음을 의미하지는 않습니다.
런타임은 이 관찰을 관리합니다. 클라이언트는 서버 이름에 따라 캐시된 상태를 대체해서는 안 됩니다.
인벤토리는 동시 그래프 교체를 제한된 횟수만큼 다시 시도하고 일관된 스냅샷을 가져올 수 없는 경우 오류를 반환합니다. 그래프 경합을 숨기기 위해 live를 생략하는 일은 절대 없습니다.
이름 전용 startServer 또는 restartServer는 콜드 세션이 다시 시작된 후 list를 먼저 호출하지 않고도 요청된 서버만 조회 및 초기화합니다.
여기에는 사용자 및 플러그인 구성과 githubMcpToolConfig를 통해 구성된 기본 제공 GitHub 서버가 포함됩니다. 구성된 다른 서버를 시작하지도 않고, 비활성화된 상태, 인증 요구 사항, 샌드박스 정책 또는 구성 원본 우선 순위를 재정의하지도 않습니다.
Node.js/ TypeScript
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
const session = await client.createSession({
model: "gpt-5",
mcpServers: {
// Local MCP server (stdio)
"my-local-server": {
type: "local",
command: "node",
args: ["./mcp-server.js"],
env: { DEBUG: "true" },
cwd: "./servers",
tools: ["*"], // "*" = all tools, [] = none, or list specific tools
timeout: 30000,
},
// Remote MCP server (HTTP)
"github": {
type: "http",
url: "https://api.githubcopilot.com/mcp/",
headers: { "Authorization": "Bearer ${TOKEN}" },
tools: ["*"],
},
},
});
Python
import asyncio
from copilot import CopilotClient
from copilot.session import PermissionHandler
async def main():
client = CopilotClient()
await client.start()
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-5", mcp_servers={
# Local MCP server (stdio)
"my-local-server": {
"type": "local",
"command": "python",
"args": ["./mcp_server.py"],
"env": {"DEBUG": "true"},
"cwd": "./servers",
"tools": ["*"],
"timeout": 30000,
},
# Remote MCP server (HTTP)
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {"Authorization": "Bearer ${TOKEN}"},
"tools": ["*"],
},
})
response = await session.send_and_wait("List my recent GitHub notifications")
print(response.data.content)
await client.stop()
asyncio.run(main())
Go
package main
import (
"context"
"log"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-5",
MCPServers: map[string]copilot.MCPServerConfig{
"my-local-server": copilot.MCPStdioServerConfig{
Command: "node",
Args: []string{"./mcp-server.js"},
Tools: []string{"*"},
},
},
})
if err != nil {
log.Fatal(err)
}
defer session.Disconnect()
// Use the session...
}
.NET
using GitHub.Copilot;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
McpServers = new Dictionary<string, McpServerConfig>
{
["my-local-server"] = new McpStdioServerConfig
{
Command = "node",
Args = new List<string> { "./mcp-server.js" },
Tools = new List<string> { "*" },
},
},
});
세션당 구성된 서버 사용 안 함
세션에서 실행해서는 안 되는 정확한 MCP 서버 이름으로 설정합니다 disabledMcpServers .
설정은 개별 만들기 또는 다시 시작 요청으로 범위가 지정됩니다. 전역 MCP 설정 또는 서버 구성을 수정하지 않습니다.
const session = await client.createSession({
mcpServers: {
filesystem: { type: "local", command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "."] },
github: { type: "http", url: "https://api.githubcopilot.com/mcp/" },
},
disabledMcpServers: ["github"],
});
| SDK | 구성 속성 |
|---|---|
| Node.js | disabled |
| Python | disabled_mcp_ |
| Go | Disabled |
| .NET | Disabled |
| Java | set |
| 러스트 | with_disabled_ |
세션 생성 시 및 콜드 재개 시에는 비활성화된 서버가 시작되지 않으며 런타임은 해당 서버의 인증을 시작하지 않습니다. 상주 이력서는 런타임이 이미 생성된 서버를 실행 취소할 수 없습니다. 이름은 정확히 일치합니다.
프롬프트 나열 및 조회
실험적으로 생성된 MCP 네임스페이스는 와이어 프로토콜 JSON-RPC 메서드 session.mcp.prompts.list 및 session.mcp.prompts.get를 노출합니다. 아래 언어별 SDK 접근자를 사용하여 이를 호출합니다. 이러한 메서드는 현재 세션에서 하나의 연결된 서버를 대상으로 합니다. 여러 서버의 결과를 결합하지 않습니다.
| SDK | 프롬프트 목록 | 프롬프트 받기 |
|---|---|---|
| Node.js | session.rpc.mcp.prompts.list(...) | session.rpc.mcp.prompts.get(...) |
| Python | session.rpc.mcp.prompts.list(...) | session.rpc.mcp.prompts.get(...) |
| Go | session.RPC.MCP.Prompts().List(...) | session.RPC.MCP.Prompts().Get(...) |
| .NET | session.Rpc.Mcp.Prompts.List | session.Rpc.Mcp.Prompts.Get |
| Java | session.get | session.get |
| 러스트 | session.rpc().mcp().prompts().list(...) | session.rpc().mcp().prompts().get(...) |
목록에는 serverName가 필요하며 선택적인 불투명 cursor도 허용됩니다. 각 호출은 타입이 지정된 프롬프트 정의의 한 페이지와 선택적 nextCursor를 반환합니다.
다른 목록 API 요청에서 해당 커서를 전달하여 다음 페이지를 요청합니다. 정의에는 이름, 선택적 제목 및 설명, 인수 정의가 포함됩니다.
생략된 인수 required 플래그는 false와 구분됩니다.
프롬프트를 가져오려면 arguments와 serverName가 필요하며, 값이 문자열인 선택적 promptName 사전이 필요합니다.
arguments를 생략하면 MCP 요청의 인수가 누락됩니다. {}를 전달하면 명시적으로 빈 사전이 전송됩니다.
런타임은 서버에 대해 이러한 구분을 유지합니다. 결과에는 유형이 지정된 역할과 불투명한 JSON content이 있는 선택적 설명 및 순서가 지정된 메시지가 포함됩니다.
각 콘텐츠 블록의 type를 해석하기 전에 검사합니다. 콘텐츠는 텍스트로 평면화되지 않습니다. 중첩된 리소스, 주석, 메타데이터, 익숙하지 않은 콘텐츠 형식 및 추가 콘텐츠 필드는 해당 JSON 구조를 유지합니다. 형식화된 설명자, 메시지 및 결과 엔벌로프의 서버 확장은 아래 additionalProperties에서 사용할 수 있습니다.
additionalProperties라는 이름의 서버 확장 자체는 병합되지 않고 해당 맵 내의 항목으로 유지됩니다.
프로토콜의 최상위 resultType: "complete" 판별기는 런타임에서 사용되며 SDK 필드 또는 서버 확장으로 반환되지 않습니다.
런타임이 1MiB 캡처 제한을 초과하는 stdio 응답 프레임을 포함하여 원시 응답을 유지할 수 없는 경우 요청이 명시적으로 실패합니다.
반환된 프롬프트 메시지는 모델에 자동으로 전송되거나 도구를 실행하거나 참조된 리소스를 가져오는 데 사용되지 않습니다. 애플리케이션은 결과를 사용하는 방법을 결정합니다. 해당 결과를 생성하는 동안 MCP 서버는 여러 차례의 왕복 상호작용을 통해 샘플링 또는 정보 요청을 요청할 수 있습니다. 이러한 요청은 다른 MCP 작업과 동일한 구성된 호스트 응답자를 사용합니다. 프롬프트 검색은 추가 권한을 부여하거나 호스트의 결정을 무시하지 않습니다. 누락된 응답자 또는 응답자 오류가 요청을 실패하게 하며, elicitation decline은 변경되지 않은 상태로 서버에 반환됩니다. 상태 전용 연속은 두 응답자 어느 쪽도 호출하지 않습니다.
기존 mcp.prompts.list_changed 세션 이벤트 후 지정된 서버의 프롬프트를 다시 나열하여 애플리케이션 보기를 새로 고칩니다.
MCP 시작 전에 샌드박스 정책 적용
검색된 루트 구성, 플러그인 또는 명시적으로 구성된 MCP 서버가 시작되기 전에, 생성 중에 샌드박스 정책을 적용하려면 createSession을(를) resumeSession 또는 sandboxConfig에 전달합니다.
session.rpc.options.update({ sandboxConfig })와 동일한 구성을 허용합니다.
const sandboxConfig = {
enabled: true,
sandboxMcpServers: true,
userPolicy: { network: { allowOutbound: false } },
};
const session = await client.createSession({
onPermissionRequest: approveAll,
sandboxConfig,
});
콜드 재개 시 구성을 다시 적용합니다. 생략은 상주 세션의 현재 정책을 유지합니다. 상주 재개는 이미 시작된 프로세스를 실행 취소할 수 없습니다. 관리 정책 유효성 검사에서는 옵션 업데이트와 동일한 직접 호스트 의미 체계를 사용합니다. 충돌하는 요청은 managed_sandbox_policy_conflict가 data.code로 설정된 JSON-RPC 오류와 함께 샌드박스 처리되지 않은 세션으로 되돌아가는 대신 만들기 또는 다시 시작에 실패합니다. 런타임은 이 명시적 호스트 구성에 설정에서 파생된 sandboxConfigSource를 할당하지 않습니다.
관리되는 정책이 구성을 정규화한 경우를 포함하여 이후의 동일한 options.update({ sandboxConfig })은 MCP 서버를 다시 시작하지 않습니다. 다른 적용되는 MCP 샌드박스 정책은 일반적인 다시 시작 동작을 유지합니다.
ConnectResult(server.connect)에서 반환된 version 런타임을 애플리케이션에서 이 기능에 필요한 최소 런타임 릴리스와 비교하여 확인합니다. SDK 프로토콜 버전은 기능별 지원 여부를 나타내는 신호가 아닙니다. 이전 런타임은 알 수 없는 만들기/다시 시작 필드를 무시하므로 이를 지원하는 애플리케이션은 열 때 sandboxConfig를 보내고 후속 옵션 업데이트에서 이를 반복할 수 있습니다. 해당 업데이트는 지원되는 런타임에서는 무해하지만 업데이트가 도착하기 전에 이전 런타임은 MCP를 시작할 수 있습니다. 첫 프로세스부터 격리가 반드시 필요한 경우 지원되는 런타임 버전을 요구하십시오.
도구 구성
tools 필드를 사용하여 MCP 서버에서 사용할 수 있는 도구를 제어할 수 있습니다.
모든 도구 허용
MCP 서버에서 제공하는 모든 도구를 사용하도록 설정하는 데 사용합니다 "*" .
tools: ["*"]
특정 도구 허용
액세스를 제한하는 도구 이름 목록을 제공합니다.
tools: ["bash", "edit"]
나열된 도구만 에이전트에서 사용할 수 있습니다.
모든 도구 사용 안 함
빈 배열을 사용하여 모든 도구를 사용하지 않도록 설정합니다.
tools: []
Notes
tools필드는 허용되는 도구를 정의합니다.- 별도의
allow구성이나disallow구성이 없습니다. 도구 액세스는 이 목록을 통해 직접 제어됩니다.
빠른 시작: 파일 시스템 MCP 서버
공식 @modelcontextprotocol/server-filesystem MCP 서버를 사용하는 전체 작업 예제는 다음과 같습니다.
import { CopilotClient } from "@github/copilot-sdk";
async function main() {
const client = new CopilotClient();
// Create session with filesystem MCP server
const session = await client.createSession({
mcpServers: {
filesystem: {
type: "local",
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
tools: ["*"],
},
},
});
console.log("Session created:", session.sessionId);
// The model can now use filesystem tools
const result = await session.sendAndWait({
prompt: "List the files in the allowed directory",
});
console.log("Response:", result?.data?.content);
await session.disconnect();
await client.stop();
}
main();
Output:
Session created: 18b3482b-bcba-40ba-9f02-ad2ac949a59a
Response: The allowed directory is `/tmp`, which contains various files
and subdirectories including temporary system files, log files, and
directories for different applications.
팁
MCP 서버 디렉터리에서 MCP 서버를 사용할 수 있습니다. 인기 있는 옵션에는 @modelcontextprotocol/server-github, @modelcontextprotocol/server-sqlite및 @modelcontextprotocol/server-puppeteer.
구성 옵션
로컬/stdio 서버
| 재산 | Type | 필수 | Description |
|---|---|---|---|
type | |||
"local" 또는 "stdio" | No | 서버 유형(기본값: 로컬) | |
command | string | Yes | 실행할 명령 |
args | string[] | Yes | 명령 인수 |
env | object | No | 환경 변수 |
cwd | string | No | 작업 디렉터리 |
tools | string[] | No | 모든 사용자에게 허용할 도구(["*"] 또는, [] 아무에게도 허용하지 않을 도구) |
timeout | number | No | 시간 제한(밀리초) |
원격 서버(HTTP/SSE)
| 재산 | Type | 필수 | Description |
|---|---|---|---|
type | |||
"http" 또는 "sse" | Yes | 서버 유형 | |
url | string | Yes | 서버 URL |
headers | object | No | HTTP 헤더(예: 인증용) |
oauthClientId | string | No | 정적으로 구성된 OAuth 클라이언트에 대한 비어 있지 않은 클라이언트 ID |
oauthScopes | string[] | No | 유효한 RFC 6749 범위 토큰의 비어있지 않은 배열입니다. |
oauthClientId는 서버 챌린지에서 범위를 생략하거나 빈 범위를 제공하는 경우, 보호된 리소스 메타데이터 대체 전에 필요하며 사용됩니다. | |||
oauthPublicClient | boolean | No | 구성된 OAuth 클라이언트가 공용이며 클라이언트 암호가 필요하지 않은지 여부 |
oauthGrantType | string | No | 구성된 클라이언트에 대한 OAuth 권한 부여 유형(예: client_credentials) |
tools | string[] | No | 사용을 가능하게 하는 도구 |
timeout | number | No | 시간 제한(밀리초) |
원격 서버의 OAuth 소유 설정
각 인증 시도에 대해 하나의 OAuth 소유권 모델을 선택하세요.
- 런타임 관리 루프백: 리디렉션 URI 없이
session.mcp.oauth.login를 호출합니다. 런타임은 로컬 콜백 수신기를 열고 검색, PKCE, 상태 유효성 검사, 토큰 교환, 저장, 새로 고침 및 재연결을 담당합니다. - 런타임 관리 호스트 콜백: 신뢰할 수 있는 공용 HTTPS 리디렉션 URI로
session.mcp.oauth.login을 호출합니다. 호스트는 콜백을 수신하지만 OAuth 프로토콜 및 자격 증명에 대한 제어권은 계속 런타임에 있습니다. - 호스트 관리 OAuth: SDK의 MCP 인증 요청 처리기를 사용하고 호스트에서 획득한 액세스 토큰을 반환합니다. 호스트가 인증 및 새로 고침 토큰을 보유합니다.
런타임 관리 호스트 콜백을 사용하는 인증 시도에 대해 호스트 관리 OAuth 처리기를 등록하지 마세요. 원격 서버가 needs-auth 상태가 될 때까지 기다린 다음, 서버 이름 및 콜백 URI를 사용하여 생성된 session.rpc.mcp.oauth.login 메서드를 직접 호출합니다.
{
"serverName": "remote-mcp",
"redirectUri": "https://agent.example.com/oauth/callback"
}
선택한 정적, CIMD 또는 동적으로 등록된 OAuth 클라이언트는 해당 정확한 URI를 명시해야 합니다. URI는 HTTPS를 사용해야 하며 쿼리 또는 조각을 포함해서는 안 됩니다.
브라우저 상호 작용이 필요한 경우 결과에는 authorizationId 및 authorizationUrl이 포함됩니다. 사용자의 브라우저에서 authorizationUrl을 열고 대상 세션과 함께 authorizationId을 유지합니다.
권한 부여 서버가 사용자를 엔드포인트로 리디렉션한 후 생성된 session.rpc.mcp.oauth.complete 메서드를 호출합니다.
{
"authorizationId": "<opaque-state>",
"callbackUrl": "https://agent.example.com/oauth/callback?code=...&state=..."
}
구성된 공용 리디렉션 원본 및 경로와 콜백의 원래 쿼리를 사용해 callbackUrl를 생성합니다. 내부 서비스 URL을 전달하지 말고, 클라이언트가 제공한 Forwarded 또는 X-Forwarded-* 헤더를 신뢰하지 마세요. 런타임은 전달을 수락하기 전에 원본, 포트, 경로, 상태 및 OAuth 응답의 유효성을 검사합니다. 토큰 교환, 상태 유지, MCP 재연결 후 비동기적으로 계속 진행됩니다.
거부된 액세스 토큰을 런타임에 다시 반환
reason: "refresh" 및 runtimeRefreshSupported: true가 있는 호스트 OAuth 요청의 경우 처리기는 대체 액세스 토큰을 획득하는 대신 { "kind": "runtimeRefresh" }를 반환할 수 있습니다.
런타임은 원래 권한 부여 작업 내에서 저장된 grant를 사용하여 비대화형 갱신을 수행합니다. 새 동의 흐름을 시작하거나 독립적인 authenticationStateChanged 새로 고침 RPC를 호출하지 않습니다.
대체는 저장된 grant의 출처 정보를 유지하므로 나중에도 범위가 지정된 저장 토큰 적용을 계속 사용할 수 있습니다. 호스트에서 직접 제공하는 토큰은 저장된 토큰으로 표시되지 않으며 해당 adoption 경로로 덮어쓸 수 없습니다.
보류 중인 요청이 지원을 표시하는 경우에만 이 응답을 반환합니다. 기능이 없으면 false이며 레거시 토큰/취소 계약을 유지합니다. 처리기가 기능 없이 요청에 대한 핸드오프를 반환하는 경우 SDK가 대신 cancelled를 전송하므로 보류 중인 요청이 열린 상태로 유지되지 않습니다. 제공된 토큰이 핸드오프보다 우선하며 취소는 취소로 유지됩니다.
| SDK | Capability | 핸드오프 결과 |
|---|---|---|
| Node.js | request.runtime | { kind: "runtimeRefresh" } |
| Python | request["runtime | {"kind": "runtimeRefresh"} |
| Go | ||
MCPAuth capability 매개변수 | MCPAuth | |
| .NET | Mcp | Mcp |
| Java | ||
Mcp capability 매개변수 | Mcp | |
| 러스트 | Mcp | Mcp |
응답 수락은 새로 고침, 다시 연결 또는 도구 완성이 아니라 핸드오프를 확인합니다. 승인된 핸드오프 mcp.oauth_completed의 경우 원래 승인 보류가 최종 결과에 도달하면 한 번 내보내집니다.
outcome 기존 값만 사용합니다. 복구에 성공하면 cancelled, 취소되거나 실패하면 token입니다. 지속형 mcp.oauth_recovery_completed 이벤트는 동일한 requestId 및 serverName를 유지하며, 다시 연결을 포함한 최종 결과(예: succeeded, cancelled 또는 failed)를 구분합니다. 이 이벤트보다 이전의 SDK 버전은 알 수 없는 이벤트 유형으로 처리됩니다.
런타임이 runtimeRefresh 응답을 수락할 때까지 기존 회신은 이전 의미를 유지합니다. 호스트 { kind: "cancelled" } 회신은 요청을 거절합니다. refresh 요청의 경우 런타임은 재인증을 요청할 수 있습니다.
호스트가 회신하지 않으면 런타임은 캐시된 자격 증명을 포함하여 일반 로컬 OAuth 처리를 대신 사용하며 mcp.oauth_recovery_completed 이벤트를 내보내지 않습니다.
이 변경 내용은 호스트 cancelled 회신을 중지로 다시 분류하지 않습니다. 원래 호출은 승인된 runtimeRefresh 핸드오프를 통해서만 유지됩니다.
수락 후에는 자격 증명을 설치한 다음 원래 호출을 다시 시도할 수 있으며, 기존 세션, 구성, 정책 및 권한 제약을 유지한 채 다시 연결할 수도 있습니다. 주 턴을 중지하거나 세션을 종료하면 원래 권한 부여 예약이 취소됩니다. 중지된 호출은 나중에 결과를 다시 시도하거나 반환할 수 없습니다. 이미 발급된 회전 권한 부여 교환은 취소 후 대체 항목의 저장을 완료할 수 있지만 오래된 자격 증명을 설치하거나, 다시 연결하거나, 취소된 호출을 다시 시작할 수는 없습니다.
사용할 수 없는 저장된 승인 또는 실패한 갱신은 대화형 재인증 요청 없이 원래 호출을 종료합니다. 실패한 다시 연결은 호출도 종료합니다. 토큰을 성공적으로 가져오는 것은 성공적인 도구 결과가 아닙니다.
동시 호출은 정확히 동일한 진행 중인 권한 부여 시도에 합류하여 최종 결과를 받습니다. 연결된 서버, 보존된 액세스 토큰 또는 나중에 성공한 시도는 해당 시도가 성공했다는 증거가 아닙니다. 남은 각 호출은 다시 시도하기 전에 자체 카탈로그 및 도구 권한을 다시 확인합니다. 병합된 실패는 다른 대화형 권한 승인을 시작하지 않습니다.
OAuth HTTP 시간 제한은 전체 핸드오프 또는 grant-storage 정산이 아닌 개별 요청에 적용됩니다. 취소는 발행된 교환 작업이 정산되기 전에 반환될 수 있으며, 세션 폐기는 추적된 정산 워커를 기다립니다. 전체 정산 기한은 없으므로 호스트는 취소, 인계 승인 또는 HTTP 시간 제한을 모든 스토리지 작업이 완료되었다는 증거로 취급해서는 안 됩니다.
세션 범위의 MCP 진단
세션을 만들거나 다시 시작할 때 MCP 진단을 사용하도록 설정하려면 diagnostics: { sources: { mcp: { level: "debug" } } }를 설정합니다. 모든 소스는 기본적으로 off로 설정됩니다.
사용 가능한 수준은 error, warning, info``debug및 trace. 이 설정은 클라이언트의 프로세스 수준 logLevel과 별개입니다.
경고
진단 항목은 사용 가능한 모든 수준에서 사용자 제공 또는 서버 제공 콘텐츠를 포함할 수 있습니다. warning 이상에서는 서버 stderr를 포함할 수 있으며, debug 및 trace에서는 MCP 페이로드, 도구 인수 및 경로를 추가로 포함할 수 있습니다. 모든 항목을 민감한 항목으로 처리합니다. 항목을 원격 분석으로 자동으로 업로드하거나 명시적인 호스트 동작 없이 내보내지 마세요.
생성된 session.rpc.diagnostics API를 통해 호스트는 세션 범위의 제한된 메모리 내 진단을 구성하고 읽을 수 있습니다. MCP는 첫 번째이자 현재 지원되는 유일한 원본입니다. 읽기 시 sources: ["mcp"]를 명시적으로 선택합니다. 읽기는 캡처를 활성화하지 않습니다. 출력 화면당 하나의 중지 가능한 읽기 루프를 사용하고 커서를 유지합니다. 읽기 루프는 커서 및 프레젠테이션을 소유합니다. 런타임은 캡처, 필터링, 보존, 커서 만료 및 웨이크업을 소유합니다.
import { approveAll, CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
const stop = new AbortController();
const appendLine = (line: string) => console.log(line);
await client.start();
const session = await client.createSession({
onPermissionRequest: approveAll,
diagnostics: { sources: { mcp: { level: "debug" } } },
});
try {
let cursor: string | undefined;
while (!stop.signal.aborted) {
const page = await session.rpc.diagnostics.read({
sources: ["mcp"],
cursor,
max: 100,
waitMs: 30_000,
});
if (page.cursorStatus === "expired") {
appendLine("MCP diagnostic entries were dropped.");
}
for (const entry of page.entries) {
const detail = entry.details.data ? ` ${entry.details.data}` : "";
appendLine(
`${entry.timestamp} [${entry.level}] [${entry.source}:${entry.details.serverName}] ${entry.message}${detail}`,
);
}
cursor = page.cursor;
}
} finally {
await session.disconnect();
await client.stop();
}
중단 신호는 현재 제한된 읽기가 완료된 후 루프를 중지합니다. RPC 호출에 전달되지 않습니다. 캡처를 사용하지 않도록 설정하면 미해결 읽기를 깨웁니다.
MCP 시작은 지연 시작입니다. 진단을 사용하거나 읽어도 서버가 시작되지 않습니다.
세션 생성 시 mcpServers를 구성한 다음, 세션을 정상적으로 사용하거나 설치된 서버의 문제 해결을 위해 session.rpc.mcp.startServer({ serverName })를 호출하여 모델 요청을 하지 않고 초기화 문제를 해결합니다.
각 레코드에는 source: "mcp", 타임스탬프, 심각도, 메시지, 그리고 루트가 아닌 에이전트의 경우 선택적 agentId가 있습니다.
details 형식에는 수명 주기, 프로토콜, HTTP 또는 stderr 범주, 서버 이름, 각 연결 시도마다 새로운 connectionId, 선택적 프로토콜 방향 및 진단 데이터가 포함됩니다.
MCP 보존은 세션당 1,024개의 레코드와 4MiB로 제한됩니다. 인코딩된 개별 레코드는 16KiB로 제한되며 단축되면 truncated가 포함됩니다. 기본적으로 100개의 레코드를 읽고, 최대 500개의 레코드를 허용하며, 다른 리더의 데이터를 소비하지 않습니다.
만료된 커서에 droppedCount가 있으면 알려진 손실을 표시하는 데 사용합니다.
성공한 모든 읽기는 빈 읽기를 포함하여 커서 및 커서 상태를 반환합니다. 레코드가 도착하지 않는 경우에도 반환된 커서를 유지합니다. 커서는 해당 선택에 속합니다. 해당 선택을 변경할 때 커서 없이 시작하세요.
형식이 잘못된 커서 및 잘못된 숫자 범위와 마찬가지로 누락되거나 비어 있거나 중복되거나 지원되지 않는 원본이 거부됩니다. 기록이나 캡처 설정은 세션 기록에 저장되지 않습니다.
MCP 캡처를 사용하지 않도록 설정하고 보존된 버퍼를 지우려면 session.rpc.diagnostics.configure({ sources: { mcp: { level: "off" } } })을 호출하여 합니다. 구성 업데이트는 명시적으로 명명된 원본만 업데이트하고 유효 소스 수준을 반환합니다. 비어 있거나 알 수 없는 원본 구성이 거부되었습니다. 나중에 지원되는 다른 원본을 추가해도 기존 호출자에게 자동으로 적용되지는 않습니다.
호스트의 읽기 루프도 중지합니다. 읽기 작업은 로깅이 해제된 동안 대기하지 않고 즉시 반환됩니다. 로깅을 사용하지 않도록 설정하면 대기 중인 롱 폴링이 깨어납니다.
diagnostics를 상주 재개 중에 생략하면 현재 구성이 유지됩니다. 콜드 로드된 세션에는 새 옵트인이 필요합니다.
초기 off 상태에서 진단을 사용하도록 설정하면 이미 라이브 MCP 연결에 대한 캡처를 시작할 수 있습니다. 진단을 사용하지 않도록 설정한 configure({ sources: { mcp: { level: "off" } } })후 다시 사용하도록 설정하면 동일한 라이브 연결 및 기존 연결 ID에 대한 캡처를 다시 시작할 수 있습니다. 진단을 사용하지 않도록 설정했을 때 이미 진행 중이던 레코드는 폐기됩니다.
런타임은 항목이 이 API에 도달하기 전에 HTTP 진단에서 구성되고 구조적으로 인식되는 자격 증명을 제거하지만, 이는 임의의 서버 제공 비밀이 없다는 보장은 아닙니다. 요청 또는 응답 헤더 맵을 노출하지 않습니다. 선택한 메타데이터(예: Content-Type, Accept 및 MCP-Protocol-Version)만 캡처할 수 있지만 해당 값은 여전히 신뢰할 수 없으며 민감한 콘텐츠를 포함할 수 있습니다. 인증 헤더, 쿠키, 세션 ID, 쿼리 값, URL userinfo 및 조각은 생략됩니다. URL 경로는 문제 해결을 위해 유지되므로 경로 세그먼트에 자격 증명을 배치하지 마세요.
프로토콜 페이로드 및 stderr는 사용자 콘텐츠 또는 임의의 서버 제공 비밀을 포함할 수도 있습니다.
Troubleshooting
도구가 표시되지 않거나 호출되지 않음
-
MCP 서버가 올바르게 시작되는지 확인
- 명령 및 인수가 올바른지 확인합니다.
- 시작 시 서버 프로세스가 충돌하지 않는지 확인
- stderr에서 오류 출력 찾기
-
도구 구성 확인
tools이(가)["*"]로 설정되어 있거나 필요한 특정 도구가 나열되어 있는지 확인하세요.- 빈 배열
[]은 도구가 활성화되지 않음을 의미합니다.
-
원격 서버에 대한 연결 확인
- URL에 액세스할 수 있는지 확인
- 인증 헤더가 올바른지 확인
일반적인 문제
| Issue | 해결 방법 |
|---|---|
| "MCP 서버를 찾을 수 없습니다." | 명령 경로가 올바르고 실행 가능한지 확인합니다. |
| "연결 거부됨"(HTTP) | URL을 확인하고 서버가 실행 중인지 확인합니다. |
| "시간 제한" 오류 | 값을 증가시키거나 timeout 서버 성능을 확인하십시오. |
| 도구가 작동하지만 호출되지 않음 | 프롬프트에 도구의 기능이 명확하게 필요한지 확인합니다. |
자세한 디버깅 지침은 MCP 서버 디버깅 가이드 을 참조하세요.
관련 리소스
- 모델 컨텍스트 프로토콜 사양
- MCP 서버 디렉터리 - 커뮤니티 MCP 서버
- GitHub MCP 서버 - 공식 GitHub MCP 서버
- 첫 번째 Copilot 기반 앱 빌드 - SDK 기본 사항 및 사용자 지정 도구
- 디버깅 가이드 - SDK 전체 디버깅
참고하십시오
- MCP 서버 디버깅 가이드 - 자세한 MCP 문제 해결
- 문제 #9 - 원래 MCP 도구 사용 질문
- 문제 #36 - MCP 설명서 추적 문제