burkut-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.js +150 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +81 -0
- package/dist/tools.d.ts +12 -0
- package/dist/tools.js +207 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# burkut-mcp 🦅
|
|
2
|
+
|
|
3
|
+
> **Model Context Protocol (MCP) Server for Turkish Financial Markets (BIST, TEFAS, KAP, IPOs, Macro) powered by Bürküt API.**
|
|
4
|
+
|
|
5
|
+
`burkut-mcp`, Türkiye finans piyasası verilerini (Borsa İstanbul hisseleri, TEFAS yatırım fonları, KAP bildirimleri, halka arzlar, temettüler ve makroekonomik veriler) doğrudan **Claude Desktop**, **Cursor**, **Windsurf** ve diğer LLM tabanlı yapay zeka ajanlarına bağlayan resmi olmayan/açık kaynak bir MCP sunucusudur.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ⚡ Hızlı Başlangıç (Quickstart)
|
|
10
|
+
|
|
11
|
+
Kurulum yapmanıza gerek yoktur, `npx` ile anında çalıştırılabilir:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx -y burkut-mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 1. Claude Desktop ile Kullanım
|
|
18
|
+
|
|
19
|
+
Claude Desktop yapılandırma dosyanızı açın:
|
|
20
|
+
* **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
21
|
+
* **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
22
|
+
|
|
23
|
+
Aşağıdaki yapılandırmayı ekleyin:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"burkut": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "burkut-mcp"],
|
|
31
|
+
"env": {
|
|
32
|
+
"BURKUT_API_KEY": "YOUR_API_KEY_HERE"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> **Not:** `BURKUT_API_KEY` opsiyoneldir. Anahtar girmeden de temel halka açık modda çalışır. Ancak daha yüksek kota ve kesintisiz erişim için [burkut.com/developers](https://burkut.com/developers) adresinden ücretsiz API Key alabilirsiniz.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### 2. Cursor IDE ile Kullanım
|
|
44
|
+
|
|
45
|
+
Cursor Ayarları (`Settings`) -> `Features` -> `MCP Servers` -> `Add New MCP Server`:
|
|
46
|
+
* **Name:** `burkut`
|
|
47
|
+
* **Type:** `command`
|
|
48
|
+
* **Command:** `npx -y burkut-mcp`
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🛠️ Desteklenen Araçlar (MCP Tools)
|
|
53
|
+
|
|
54
|
+
| Tool | Açıklama |
|
|
55
|
+
| :--- | :--- |
|
|
56
|
+
| `burkut_search_funds` | TEFAS fonlarını koda, isme veya kategoriye göre filtreler; 1 ay, 3 ay, 6 ay ve 1 yıllık getirilerine göre sıralar. |
|
|
57
|
+
| `burkut_get_fund_detail` | Belirli bir fonun (örn: `MAC`, `TI2`, `TCD`) tüm getiri periyotları, risk seviyesi ve güncel fiyat detaylarını çeker. |
|
|
58
|
+
| `burkut_get_stock_quote` | BIST hisselerinin (örn: `THYAO`, `ASELS`, `KCHOL`) anlık/güncel fiyat, değişim % ve hacim verilerini getirir. |
|
|
59
|
+
| `burkut_get_kap_announcements` | Kamuyu Aydınlatma Platformu'na (KAP) düşen şirket bildirimlerini veya genel piyasa bültenini çeker. |
|
|
60
|
+
| `burkut_get_ipo_calendar` | Aktif ve yaklaşan Halka Arz (IPO) takvimini, lot fiyatlarını ve talep toplama tarihlerini listeler. |
|
|
61
|
+
| `burkut_get_dividends` | BIST şirketlerinin temettü geçmişi, hisse başı net ödeme ve temettü verimi oranlarını getirir. |
|
|
62
|
+
| `burkut_get_macro_indicators` | Türkiye resmi enflasyon oranları (TÜFE/ÜFE), serbest piyasa döviz kurları (USD/TRY, EUR/TRY) ve altın fiyatlarını getirir. |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 💬 Örnek İstemler (Prompt Örnekleri)
|
|
67
|
+
|
|
68
|
+
Claude Desktop veya Cursor Composer'da doğrudan şunları sorabilirsiniz:
|
|
69
|
+
|
|
70
|
+
* *"Bana TEFAS'taki hisse senedi fonları arasında son 1 yılda en yüksek getiri sağlayan ilk 5 fonu listele ve yıllık getirilerini göster."*
|
|
71
|
+
* *"MAC ve TI2 fonlarının risk seviyelerini ve son 6 aylık performanslarını karşılaştır."*
|
|
72
|
+
* *"Bugün KAP'a düşen önemli şirket bildirimlerini özetle."*
|
|
73
|
+
* *"Bu hafta talep toplayacak veya aktif olan halka arzlar hangileri? Fiyatları ve tarihleri nedir?"*
|
|
74
|
+
* *"FROTO ve TUPRS'ın son temettü dağıtım oranlarını karşılaştır."*
|
|
75
|
+
* *"Türkiye'deki son açıklanan yıllık TÜFE enflasyon oranı ile güncel dolar kurunu getir."*
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 🔧 Geliştirme (Local Development)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/sametakan29/burkut-sdks.git
|
|
83
|
+
cd burkut-sdks/mcp
|
|
84
|
+
npm install
|
|
85
|
+
npm run build
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Yerel test için:
|
|
89
|
+
```bash
|
|
90
|
+
node dist/index.js
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Ortam Değişkenleri:
|
|
94
|
+
* `BURKUT_API_KEY`: Bürküt Developer API anahtarınız (opsiyonel).
|
|
95
|
+
* `BURKUT_API_BASE_URL`: Hedef API adresi (Varsayılan: `https://api.burkutportfoy.com`).
|
|
96
|
+
* `BURKUT_TIMEOUT_MS`: İstek zaman aşımı süresi (Varsayılan: `15000` ms).
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 💬 Destek ve İletişim
|
|
101
|
+
|
|
102
|
+
Her türlü geri bildirim, özel veri seti talepleri veya hata bildirimleri için:
|
|
103
|
+
* **E-posta:** [destek@burkutportfoy.com](mailto:destek@burkutportfoy.com)
|
|
104
|
+
* **GitHub Issues:** [burkut-sdks/issues](https://github.com/sametakan29/burkut-sdks/issues)
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 📄 Lisans
|
|
109
|
+
|
|
110
|
+
MIT © [Bürküt](https://burkutportfoy.com)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BurkutConfig } from './config.js';
|
|
2
|
+
export declare function normalizeSymbol(sym: string): string;
|
|
3
|
+
export declare class BurkutApiClient {
|
|
4
|
+
private config;
|
|
5
|
+
constructor(config?: BurkutConfig);
|
|
6
|
+
private request;
|
|
7
|
+
getFunds(): Promise<any[]>;
|
|
8
|
+
getFundDetail(symbol: string): Promise<any>;
|
|
9
|
+
getStocks(symbols?: string[]): Promise<any[]>;
|
|
10
|
+
getStockQuote(symbol: string): Promise<any>;
|
|
11
|
+
getKapAnnouncements(symbol?: string, page?: number, size?: number): Promise<any>;
|
|
12
|
+
getKapDetail(id: string): Promise<any>;
|
|
13
|
+
getIpoList(activeOnly?: boolean): Promise<any[]>;
|
|
14
|
+
getIpoDetail(symbol: string): Promise<any>;
|
|
15
|
+
getDividends(symbol?: string): Promise<any>;
|
|
16
|
+
getInflation(): Promise<any>;
|
|
17
|
+
getForex(): Promise<any[]>;
|
|
18
|
+
getGold(): Promise<any[]>;
|
|
19
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { getConfig } from './config.js';
|
|
2
|
+
export function normalizeSymbol(sym) {
|
|
3
|
+
return sym
|
|
4
|
+
.trim()
|
|
5
|
+
.replace(/^BIST:\s*/i, '')
|
|
6
|
+
.replace(/^TEFAS:\s*/i, '')
|
|
7
|
+
.replace(/\.IS$/i, '')
|
|
8
|
+
.replace(/\.tefas$/i, '')
|
|
9
|
+
.toUpperCase();
|
|
10
|
+
}
|
|
11
|
+
export class BurkutApiClient {
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config || getConfig();
|
|
15
|
+
}
|
|
16
|
+
async request(path, options = {}) {
|
|
17
|
+
const { query, usePublicV1 } = options;
|
|
18
|
+
let resolvedPath = path;
|
|
19
|
+
const headers = {
|
|
20
|
+
'Accept': 'application/json',
|
|
21
|
+
'User-Agent': 'burkut-mcp/1.0.0',
|
|
22
|
+
};
|
|
23
|
+
if (this.config.apiKey) {
|
|
24
|
+
headers['X-API-Key'] = this.config.apiKey;
|
|
25
|
+
if (usePublicV1 && !path.startsWith('/api/public/v1')) {
|
|
26
|
+
resolvedPath = `/api/public/v1${path.replace(/^\/api\/v1/, '')}`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const url = new URL(`${this.config.baseUrl}${resolvedPath}`);
|
|
30
|
+
if (query) {
|
|
31
|
+
for (const [key, value] of Object.entries(query)) {
|
|
32
|
+
if (value !== undefined && value !== null) {
|
|
33
|
+
url.searchParams.set(key, String(value));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const controller = new AbortController();
|
|
38
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeoutMs);
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetch(url.toString(), {
|
|
41
|
+
method: 'GET',
|
|
42
|
+
headers,
|
|
43
|
+
signal: controller.signal,
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
let errorDetail = '';
|
|
47
|
+
try {
|
|
48
|
+
const errorJson = await response.json();
|
|
49
|
+
errorDetail = typeof errorJson === 'object' ? JSON.stringify(errorJson) : String(errorJson);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
errorDetail = await response.text();
|
|
53
|
+
}
|
|
54
|
+
if (response.status === 404) {
|
|
55
|
+
throw new Error(`Enstrüman veya veri bulunamadı (404 Not Found): ${path}`);
|
|
56
|
+
}
|
|
57
|
+
if (response.status === 401 || response.status === 403) {
|
|
58
|
+
throw new Error(`Yetkilendirme hatası (${response.status}): Geçersiz veya yetkisiz API Key. Lütfen burkutportfoy.com/developer üzerinden anahtarınızı kontrol edin.`);
|
|
59
|
+
}
|
|
60
|
+
if (response.status === 429) {
|
|
61
|
+
throw new Error(`İstek limiti aşıldı (429 Rate Limit): Lütfen birkaç saniye bekleyin veya daha yüksek kotalı bir plana geçin.`);
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Bürküt API Hatası (HTTP ${response.status}): ${errorDetail || response.statusText}`);
|
|
64
|
+
}
|
|
65
|
+
return (await response.json());
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
if (err.name === 'AbortError') {
|
|
69
|
+
throw new Error(`İstek zaman aşımına uğradı (${this.config.timeoutMs}ms): ${url.toString()}`);
|
|
70
|
+
}
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
clearTimeout(timeoutId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// --- Funds (TEFAS) ---
|
|
78
|
+
async getFunds() {
|
|
79
|
+
if (this.config.apiKey) {
|
|
80
|
+
return this.request('/funds', { usePublicV1: true });
|
|
81
|
+
}
|
|
82
|
+
return this.request('/api/v1/market/funds');
|
|
83
|
+
}
|
|
84
|
+
async getFundDetail(symbol) {
|
|
85
|
+
const sym = normalizeSymbol(symbol);
|
|
86
|
+
if (this.config.apiKey) {
|
|
87
|
+
return this.request(`/funds/${sym}`, { usePublicV1: true });
|
|
88
|
+
}
|
|
89
|
+
return this.request(`/api/v1/market/funds/${sym}`);
|
|
90
|
+
}
|
|
91
|
+
// --- Stocks (BIST) ---
|
|
92
|
+
async getStocks(symbols) {
|
|
93
|
+
const query = symbols && symbols.length > 0 ? { symbols: symbols.map(normalizeSymbol).join(',') } : undefined;
|
|
94
|
+
if (this.config.apiKey) {
|
|
95
|
+
return this.request('/stocks', { query, usePublicV1: true });
|
|
96
|
+
}
|
|
97
|
+
return this.request('/api/v1/market/stocks', { query });
|
|
98
|
+
}
|
|
99
|
+
async getStockQuote(symbol) {
|
|
100
|
+
const sym = normalizeSymbol(symbol);
|
|
101
|
+
if (this.config.apiKey) {
|
|
102
|
+
return this.request(`/stocks/${sym}`, { usePublicV1: true });
|
|
103
|
+
}
|
|
104
|
+
return this.request(`/api/v1/market/stocks/${sym}`);
|
|
105
|
+
}
|
|
106
|
+
// --- KAP Announcements ---
|
|
107
|
+
async getKapAnnouncements(symbol, page = 1, size = 20) {
|
|
108
|
+
const sym = symbol ? normalizeSymbol(symbol) : undefined;
|
|
109
|
+
if (sym) {
|
|
110
|
+
return this.request(`/api/v1/kap/${sym}`, { query: { page, size } });
|
|
111
|
+
}
|
|
112
|
+
return this.request('/api/v1/kap', { query: { page, size } });
|
|
113
|
+
}
|
|
114
|
+
async getKapDetail(id) {
|
|
115
|
+
return this.request(`/api/v1/kap/detail/${encodeURIComponent(id.trim())}`);
|
|
116
|
+
}
|
|
117
|
+
// --- IPO (Halka Arz) ---
|
|
118
|
+
async getIpoList(activeOnly = false) {
|
|
119
|
+
if (activeOnly) {
|
|
120
|
+
return this.request('/api/v1/ipo/active');
|
|
121
|
+
}
|
|
122
|
+
return this.request('/api/v1/ipo');
|
|
123
|
+
}
|
|
124
|
+
async getIpoDetail(symbol) {
|
|
125
|
+
return this.request(`/api/v1/ipo/${normalizeSymbol(symbol)}`);
|
|
126
|
+
}
|
|
127
|
+
// --- Dividends (Temettü) ---
|
|
128
|
+
async getDividends(symbol) {
|
|
129
|
+
if (symbol) {
|
|
130
|
+
return this.request(`/api/v1/dividends/${normalizeSymbol(symbol)}`);
|
|
131
|
+
}
|
|
132
|
+
return this.request('/api/v1/dividends');
|
|
133
|
+
}
|
|
134
|
+
// --- Macro: Inflation, Forex, Gold ---
|
|
135
|
+
async getInflation() {
|
|
136
|
+
return this.request('/api/v1/turkey/inflation');
|
|
137
|
+
}
|
|
138
|
+
async getForex() {
|
|
139
|
+
if (this.config.apiKey) {
|
|
140
|
+
return this.request('/forex', { usePublicV1: true });
|
|
141
|
+
}
|
|
142
|
+
return this.request('/api/v1/market/forex');
|
|
143
|
+
}
|
|
144
|
+
async getGold() {
|
|
145
|
+
if (this.config.apiKey) {
|
|
146
|
+
return this.request('/gold', { usePublicV1: true });
|
|
147
|
+
}
|
|
148
|
+
return this.request('/api/v1/market/gold');
|
|
149
|
+
}
|
|
150
|
+
}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function getConfig() {
|
|
2
|
+
const envBaseUrl = process.env.BURKUT_API_BASE_URL;
|
|
3
|
+
// Default to production API if not specified
|
|
4
|
+
const baseUrl = (envBaseUrl || 'https://api.burkutportfoy.com').replace(/\/+$/, '');
|
|
5
|
+
const apiKey = process.env.BURKUT_API_KEY || undefined;
|
|
6
|
+
const timeoutMs = parseInt(process.env.BURKUT_TIMEOUT_MS || '15000', 10);
|
|
7
|
+
return {
|
|
8
|
+
baseUrl,
|
|
9
|
+
apiKey,
|
|
10
|
+
timeoutMs,
|
|
11
|
+
};
|
|
12
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { BurkutApiClient } from './client.js';
|
|
6
|
+
import { TOOLS } from './tools.js';
|
|
7
|
+
import { getConfig } from './config.js';
|
|
8
|
+
async function main() {
|
|
9
|
+
const config = getConfig();
|
|
10
|
+
const client = new BurkutApiClient(config);
|
|
11
|
+
const server = new Server({
|
|
12
|
+
name: 'burkut-mcp',
|
|
13
|
+
version: '1.0.0',
|
|
14
|
+
}, {
|
|
15
|
+
capabilities: {
|
|
16
|
+
tools: {},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
// Register tools list
|
|
20
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
21
|
+
return {
|
|
22
|
+
tools: TOOLS.map((t) => ({
|
|
23
|
+
name: t.name,
|
|
24
|
+
description: t.description,
|
|
25
|
+
inputSchema: t.inputSchema,
|
|
26
|
+
})),
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
// Handle tool calls
|
|
30
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
31
|
+
const { name, arguments: args } = request.params;
|
|
32
|
+
const tool = TOOLS.find((t) => t.name === name);
|
|
33
|
+
if (!tool) {
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: `Tool '${name}' is not recognized by burkut-mcp server.`,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
isError: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const output = await tool.handler(client, args || {});
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: 'text',
|
|
50
|
+
text: output,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: 'text',
|
|
60
|
+
text: `Error executing '${name}': ${error.message || String(error)}`,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
isError: true,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const transport = new StdioServerTransport();
|
|
68
|
+
await server.connect(transport);
|
|
69
|
+
// Log to stderr (never stdout, as stdout is reserved for JSON-RPC in stdio transport)
|
|
70
|
+
console.error(`[burkut-mcp] Server running on stdio (Target API: ${config.baseUrl})`);
|
|
71
|
+
if (config.apiKey) {
|
|
72
|
+
console.error(`[burkut-mcp] API Key configured: ${config.apiKey.slice(0, 6)}...`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.error(`[burkut-mcp] Running in public mode (No BURKUT_API_KEY provided)`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
main().catch((err) => {
|
|
79
|
+
console.error('[burkut-mcp] Fatal error:', err);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
});
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BurkutApiClient } from './client.js';
|
|
2
|
+
export interface ToolDefinition {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: 'object';
|
|
7
|
+
properties: Record<string, any>;
|
|
8
|
+
required?: string[];
|
|
9
|
+
};
|
|
10
|
+
handler: (client: BurkutApiClient, args: any) => Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
export declare const TOOLS: ToolDefinition[];
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
export const TOOLS = [
|
|
2
|
+
{
|
|
3
|
+
name: 'burkut_search_funds',
|
|
4
|
+
description: 'Search and filter Turkish TEFAS mutual funds (Yatırım Fonları) by code, name, category, or top performance yields (1 ay, 3 ay, 6 ay, 1 yıl).',
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
query: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
description: 'Search keyword matching fund code (e.g. "TI2", "MAC") or name (e.g. "Hisse", "Teknoloji", "Gümüş", "Eurobond").',
|
|
11
|
+
},
|
|
12
|
+
fundType: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'Filter by fund type, e.g. "Hisse Senedi Fonu", "Para Piyasası Fonu", "Değişken Fon", "Kıymetli Madenler Fonu", "Borçlanma Araçları Fonu".',
|
|
15
|
+
},
|
|
16
|
+
sortBy: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
enum: ['yield1y', 'yield6m', 'yield3m', 'yield1m', 'dailyChangePct'],
|
|
19
|
+
description: 'Sort field (highest to lowest). Default is "yield1y".',
|
|
20
|
+
},
|
|
21
|
+
limit: {
|
|
22
|
+
type: 'number',
|
|
23
|
+
description: 'Maximum number of funds to return (default: 15, max: 50).',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
handler: async (client, args) => {
|
|
28
|
+
const raw = await client.getFunds();
|
|
29
|
+
let list = [];
|
|
30
|
+
if (Array.isArray(raw)) {
|
|
31
|
+
list = raw;
|
|
32
|
+
}
|
|
33
|
+
else if (raw && Array.isArray(raw.items)) {
|
|
34
|
+
list = raw.items;
|
|
35
|
+
}
|
|
36
|
+
if (args.query) {
|
|
37
|
+
const q = String(args.query).toLowerCase().trim();
|
|
38
|
+
list = list.filter((f) => (f.symbol && f.symbol.toLowerCase().includes(q)) ||
|
|
39
|
+
(f.name && f.name.toLowerCase().includes(q)) ||
|
|
40
|
+
(f.fundType && f.fundType.toLowerCase().includes(q)));
|
|
41
|
+
}
|
|
42
|
+
if (args.fundType) {
|
|
43
|
+
const ft = String(args.fundType).toLowerCase().trim();
|
|
44
|
+
list = list.filter((f) => f.fundType && f.fundType.toLowerCase().includes(ft));
|
|
45
|
+
}
|
|
46
|
+
const sortBy = args.sortBy || 'yield1y';
|
|
47
|
+
list.sort((a, b) => {
|
|
48
|
+
const valA = Number(a[sortBy] ?? -9999);
|
|
49
|
+
const valB = Number(b[sortBy] ?? -9999);
|
|
50
|
+
return valB - valA;
|
|
51
|
+
});
|
|
52
|
+
const limit = Math.min(Math.max(Number(args.limit) || 15, 1), 50);
|
|
53
|
+
const results = list.slice(0, limit).map((f) => ({
|
|
54
|
+
kod: f.symbol,
|
|
55
|
+
isim: f.name,
|
|
56
|
+
tur: f.fundType || f.type,
|
|
57
|
+
fiyat: f.currentPrice,
|
|
58
|
+
gunlukDegisimPct: f.dailyChangePct,
|
|
59
|
+
getiri1Ay: f.yield1m != null ? `%${f.yield1m}` : 'N/A',
|
|
60
|
+
getiri3Ay: f.yield3m != null ? `%${f.yield3m}` : 'N/A',
|
|
61
|
+
getiri6Ay: f.yield6m != null ? `%${f.yield6m}` : 'N/A',
|
|
62
|
+
getiri1Yil: f.yield1y != null ? `%${f.yield1y}` : 'N/A',
|
|
63
|
+
riskSeviyesi: f.riskLevel ?? 'N/A',
|
|
64
|
+
}));
|
|
65
|
+
return JSON.stringify({
|
|
66
|
+
totalFound: list.length,
|
|
67
|
+
returned: results.length,
|
|
68
|
+
funds: results,
|
|
69
|
+
}, null, 2);
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'burkut_get_fund_detail',
|
|
74
|
+
description: 'Get in-depth metrics and multi-period returns for a specific Turkish TEFAS fund (e.g. MAC, TI2, TCD, GLDTR).',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
symbol: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'The 3-5 character TEFAS fund code, e.g. "MAC", "TI2", "TCD", "AFT".',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
required: ['symbol'],
|
|
84
|
+
},
|
|
85
|
+
handler: async (client, args) => {
|
|
86
|
+
const fund = await client.getFundDetail(args.symbol);
|
|
87
|
+
return JSON.stringify(fund, null, 2);
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'burkut_get_stock_quote',
|
|
92
|
+
description: 'Get current price, percentage change, and volume for a Borsa Istanbul (BIST) equity (15-min delayed official feed).',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
symbol: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
description: 'Stock symbol without exchange prefix, e.g. "THYAO", "ASELS", "KCHOL", "GARAN".',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
required: ['symbol'],
|
|
102
|
+
},
|
|
103
|
+
handler: async (client, args) => {
|
|
104
|
+
const quote = await client.getStockQuote(args.symbol);
|
|
105
|
+
return JSON.stringify(quote, null, 2);
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'burkut_get_kap_announcements',
|
|
110
|
+
description: 'Fetch latest Kamuyu Aydınlatma Platformu (KAP) company disclosures, material events, financial balance sheets, and corporate announcements.',
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: {
|
|
114
|
+
symbol: {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'Optional stock symbol to filter disclosures for a specific firm (e.g. "THYAO"). If omitted, market-wide disclosures are returned.',
|
|
117
|
+
},
|
|
118
|
+
limit: {
|
|
119
|
+
type: 'number',
|
|
120
|
+
description: 'Number of notifications to retrieve (default: 10, max: 30).',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
handler: async (client, args) => {
|
|
125
|
+
const limit = Math.min(Math.max(Number(args.limit) || 10, 1), 30);
|
|
126
|
+
const data = await client.getKapAnnouncements(args.symbol, 1, limit);
|
|
127
|
+
return JSON.stringify(data, null, 2);
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'burkut_get_ipo_calendar',
|
|
132
|
+
description: 'Get the Turkish public offering (Halka Arz) calendar, including active/upcoming IPOs, offering price, dates, and subscription status.',
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
properties: {
|
|
136
|
+
activeOnly: {
|
|
137
|
+
type: 'boolean',
|
|
138
|
+
description: 'If true, only returns active and upcoming IPOs. If false, returns recent IPO history too.',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
handler: async (client, args) => {
|
|
143
|
+
const data = await client.getIpoList(Boolean(args.activeOnly));
|
|
144
|
+
return JSON.stringify(data, null, 2);
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'burkut_get_dividends',
|
|
149
|
+
description: 'Fetch dividend distribution history, dividend yield %, payout dates, and net payment per share for BIST companies.',
|
|
150
|
+
inputSchema: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: {
|
|
153
|
+
symbol: {
|
|
154
|
+
type: 'string',
|
|
155
|
+
description: 'Optional BIST stock symbol, e.g. "FROTO", "TUPRS", "EREGL". If omitted, upcoming market dividends are returned.',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
handler: async (client, args) => {
|
|
160
|
+
const data = await client.getDividends(args.symbol);
|
|
161
|
+
return JSON.stringify(data, null, 2);
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'burkut_get_macro_indicators',
|
|
166
|
+
description: 'Fetch Turkish macroeconomic indicators: official inflation rates (TÜFE / ÜFE monthly & annual), foreign exchange rates (USD/TRY, EUR/TRY), and precious metals (Gram Altın, Çeyrek Altın, Ons).',
|
|
167
|
+
inputSchema: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: {
|
|
170
|
+
category: {
|
|
171
|
+
type: 'string',
|
|
172
|
+
enum: ['all', 'inflation', 'forex', 'gold'],
|
|
173
|
+
description: 'Category to fetch: "inflation" for CPI/PPI, "forex" for FX rates, "gold" for precious metals, or "all" (default).',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
handler: async (client, args) => {
|
|
178
|
+
const category = args.category || 'all';
|
|
179
|
+
const results = {};
|
|
180
|
+
if (category === 'all' || category === 'inflation') {
|
|
181
|
+
try {
|
|
182
|
+
results.inflation = await client.getInflation();
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
results.inflation = { error: e.message };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (category === 'all' || category === 'forex') {
|
|
189
|
+
try {
|
|
190
|
+
results.forex = await client.getForex();
|
|
191
|
+
}
|
|
192
|
+
catch (e) {
|
|
193
|
+
results.forex = { error: e.message };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (category === 'all' || category === 'gold') {
|
|
197
|
+
try {
|
|
198
|
+
results.gold = await client.getGold();
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
results.gold = { error: e.message };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return JSON.stringify(results, null, 2);
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "burkut-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Model Context Protocol (MCP) server for Turkish Financial Markets (BIST, TEFAS, KAP, IPOs, Macro) powered by Bürküt API.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"burkut-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"watch": "tsc --watch",
|
|
16
|
+
"start": "node dist/index.js",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/sametakan29/burkut-sdks.git",
|
|
22
|
+
"directory": "mcp"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://burkutportfoy.com/developers",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/sametakan29/burkut-sdks/issues"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"mcp",
|
|
30
|
+
"model-context-protocol",
|
|
31
|
+
"claude",
|
|
32
|
+
"claude-desktop",
|
|
33
|
+
"cursor",
|
|
34
|
+
"windsurf",
|
|
35
|
+
"ai",
|
|
36
|
+
"bist",
|
|
37
|
+
"tefas",
|
|
38
|
+
"kap",
|
|
39
|
+
"finance",
|
|
40
|
+
"turkey",
|
|
41
|
+
"burkut"
|
|
42
|
+
],
|
|
43
|
+
"author": "Bürküt Finans <destek@burkutportfoy.com>",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.6.1",
|
|
47
|
+
"zod": "^3.24.2"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^22.13.10",
|
|
51
|
+
"typescript": "^5.7.3"
|
|
52
|
+
}
|
|
53
|
+
}
|