MCP lays out clear rules for how AI can find, connect to, and use external tools – whether it’s querying a database or running a command. This lets models go beyond their training data, making them more flexible and aware of the world around them.
MCP는 인공지능이 외부 도구를 찾고, 연결하고, 사용하는 방법에 대한 명확한 규칙을 제시합니다. 이는 데이터베이스를 조회하거나 명령을 실행하는 것과 같은 작업을 포함하며, 모델이 훈련 데이터의 한계를 넘어설 수 있도록 해줍니다. 그 결과, 모델은 더 유연하고 세상에 대한 인식 능력이 향상됩니다.
기존의 방식: 좋은 데이터와 학습법으로 뛰어난 에이전트들을 만들어 체인화 시킨다..
MCP: 에이전트가 필요한 데이터는 외부에서 직접 가져오게 하자!


spec: fastmcp, zod, node.js(>=18)
브레이브 검색엔진에서 다양한 검색을 할 수 있도록 만든 MCP
import { FastMCP } from "fastmcp";
import { z } from "zod";
import fetch from "node-fetch";
// Brave Search API 키를 환경 변수로 설정하거나 여기에 직접 입력하세요
const BRAVE_API_KEY = process.env.BRAVE_API_KEY || "YOUR_BRAVE_API_KEY";
// MCP 서버 인스턴스 생성
const server = new FastMCP({
name: "Brave Search MCP",
version: "1.0.0",
description: "MCP server for Brave Search integration"
});
// 웹 검색 도구 추가
server.addTool({
name: "braveWebSearch",
description: "Search the web using Brave Search API",
parameters: z.object({
query: z.string().describe("The search query"),
count: z.number().optional().default(10).describe("Number of results to return (default: 10)"),
country: z.string().optional().describe("Country code for localized results (e.g., 'US', 'KR')"),
safeSearch: z.enum(["strict", "moderate", "off"]).optional().default("moderate").describe("SafeSearch setting")
}),
execute: async (args) => {
const url = new URL("https://api.search.brave.com/res/v1/web/search");
// 쿼리 파라미터 설정
url.searchParams.append("q", args.query);
url.searchParams.append("count", args.count.toString());
if (args.country) {
url.searchParams.append("country", args.country);
}
if (args.safeSearch) {
url.searchParams.append("safesearch", args.safeSearch);
}
try {
const response = await fetch(url.toString(), {
method: "GET",
headers: {
"Accept": "application/json",
"X-Subscription-Token": BRAVE_API_KEY
}
});
if (!response.ok) {
throw new Error(`Brave Search API error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
// 검색 결과 포맷팅
const results = data.web?.results?.map(result => ({
title: result.title,
url: result.url,
description: result.description
})) || [];
return JSON.stringify({
totalResults: data.web?.totalResults,
results
}, null, 2);
} catch (error) {
return `Error: ${error.message}`;
}
}
});
// 뉴스 검색 도구 추가
server.addTool({
name: "braveNewsSearch",
description: "Search for news using Brave Search API",
parameters: z.object({
query: z.string().describe("The news search query"),
count: z.number().optional().default(10).describe("Number of results to return (default: 10)"),
freshness: z.enum(["past_week", "past_month", "past_year"]).optional().describe("Time period for news results")
}),
execute: async (args) => {
const url = new URL("https://api.search.brave.com/res/v1/news/search");
// 쿼리 파라미터 설정
url.searchParams.append("q", args.query);
url.searchParams.append("count", args.count.toString());
if (args.freshness) {
url.searchParams.append("freshness", args.freshness);
}
try {
const response = await fetch(url.toString(), {
method: "GET",
headers: {
"Accept": "application/json",
"X-Subscription-Token": BRAVE_API_KEY
}
});
if (!response.ok) {
throw new Error(`Brave Search API error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
// 뉴스 결과 포맷팅
const results = data.news?.results?.map(result => ({
title: result.title,
url: result.url,
description: result.description,
publishedTime: result.publishedTime,
source: result.source
})) || [];
return JSON.stringify({
totalResults: data.news?.totalResults,
results
}, null, 2);
} catch (error) {
return `Error: ${error.message}`;
}
}
});
// 이미지 검색 도구 추가
server.addTool({
name: "braveImageSearch",
description: "Search for images using Brave Search API",
parameters: z.object({
query: z.string().describe("The image search query"),
count: z.number().optional().default(10).describe("Number of results to return (default: 10)"),
aspect: z.enum(["wide", "tall", "square"]).optional().describe("Aspect ratio filter")
}),
execute: async (args) => {
const url = new URL("https://api.search.brave.com/res/v1/images/search");
// 쿼리 파라미터 설정
url.searchParams.append("q", args.query);
url.searchParams.append("count", args.count.toString());
if (args.aspect) {
url.searchParams.append("aspect", args.aspect);
}
try {
const response = await fetch(url.toString(), {
method: "GET",
headers: {
"Accept": "application/json",
"X-Subscription-Token": BRAVE_API_KEY
}
});
if (!response.ok) {
throw new Error(`Brave Search API error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
// 이미지 결과 포맷팅
const results = data.images?.results?.map(result => ({
title: result.title,
url: result.url,
imageUrl: result.imageUrl,
sourceUrl: result.sourceUrl,
width: result.width,
height: result.height
})) || [];
return JSON.stringify({
totalResults: data.images?.totalResults,
results
}, null, 2);
} catch (error) {
return `Error: ${error.message}`;
}
}
});
// 서버 시작
server.start({
transportType: "stdio",
});
https://glama.ai/blog/2024-11-25-model-context-protocol-quickstart
https://huggingface.co/blog/Kseniase/mcp#why-is-mcp-making-waves-now-and-not-last-november
https://github.com/punkpeye/fastmcp
https://github.com/punkpeye/awesome-mcp-servers