@lightcone-ai/daemon 0.9.79 → 0.10.1
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/mcp-servers/mysql/index.js +13 -5
- package/mcp-servers/mysql/manifest.json +16 -0
- package/mcp-servers/official/company-fundamentals/index.js +34 -0
- package/mcp-servers/official/company-fundamentals/manifest.json +14 -0
- package/mcp-servers/official/compliance-check/index.js +49 -0
- package/mcp-servers/official/compliance-check/manifest.json +14 -0
- package/mcp-servers/official/industry-report/index.js +34 -0
- package/mcp-servers/official/industry-report/manifest.json +14 -0
- package/mcp-servers/official/market-data-query/index.js +34 -0
- package/mcp-servers/official/market-data-query/manifest.json +14 -0
- package/mcp-servers/official/portfolio-analysis/index.js +74 -0
- package/mcp-servers/official/portfolio-analysis/manifest.json +14 -0
- package/mcp-servers/official/portfolio-read/index.js +34 -0
- package/mcp-servers/official/portfolio-read/manifest.json +14 -0
- package/mcp-servers/official/research-fetch/index.js +35 -0
- package/mcp-servers/official/research-fetch/manifest.json +14 -0
- package/mcp-servers/official/risk-metrics/index.js +34 -0
- package/mcp-servers/official/risk-metrics/manifest.json +14 -0
- package/mcp-servers/official-common/fixtures.js +273 -0
- package/mcp-servers/official-common/server.js +34 -0
- package/mcp-servers/platform/manifest.json +15 -0
- package/mcp-servers/portfolio-analysis/core.js +592 -0
- package/mcp-servers/portfolio-analysis/index.js +45 -0
- package/mcp-servers/portfolio-analysis/package-lock.json +1139 -0
- package/mcp-servers/portfolio-analysis/package.json +10 -0
- package/mcp-servers/portfolio-read/core.js +330 -0
- package/mcp-servers/portfolio-read/index.js +127 -0
- package/mcp-servers/portfolio-read/package-lock.json +1243 -0
- package/mcp-servers/portfolio-read/package.json +11 -0
- package/mcp-servers/publisher/index.js +14 -14
- package/mcp-servers/publisher/manifest.json +16 -0
- package/package.json +4 -2
- package/src/_vendor/mcp/registry.js +327 -0
- package/src/agent-manager.js +761 -188
- package/src/chat-bridge.js +567 -92
- package/src/connection.js +1 -1
- package/src/drivers/claude.js +48 -45
- package/src/drivers/codex.js +110 -8
- package/src/drivers/kimi.js +80 -35
- package/src/governance-state.js +89 -0
- package/src/index.js +34 -16
- package/src/lease-window.js +8 -0
- package/src/mcp-config.js +52 -23
|
@@ -4,12 +4,20 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import mysql from 'mysql2/promise';
|
|
6
6
|
|
|
7
|
+
function requiredEnv(name) {
|
|
8
|
+
const value = process.env[name];
|
|
9
|
+
if (!value) {
|
|
10
|
+
throw new Error(`${name} is required; configure the remote Tencent MySQL connection in .env`);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
const pool = mysql.createPool({
|
|
8
|
-
host:
|
|
9
|
-
port: Number(
|
|
10
|
-
user:
|
|
11
|
-
password:
|
|
12
|
-
database:
|
|
16
|
+
host: requiredEnv('DB_HOST'),
|
|
17
|
+
port: Number(requiredEnv('DB_PORT')),
|
|
18
|
+
user: requiredEnv('DB_USER'),
|
|
19
|
+
password: requiredEnv('DB_PASSWORD'),
|
|
20
|
+
database: requiredEnv('DB_NAME'),
|
|
13
21
|
waitForConnections: true,
|
|
14
22
|
connectionLimit: 3,
|
|
15
23
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mysql",
|
|
3
|
+
"name": "MySQL MCP Server",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "search_jobs", "classification": "cacheable" },
|
|
9
|
+
{ "name": "get_job_detail", "classification": "cacheable" },
|
|
10
|
+
{ "name": "list_jobs", "classification": "cacheable" }
|
|
11
|
+
],
|
|
12
|
+
"smoke_test": {
|
|
13
|
+
"tool": "list_jobs",
|
|
14
|
+
"arguments": { "limit": 1 }
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { FUNDAMENTAL_FIXTURES, fixtureResponse, normalizeTicker } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
await startFixtureServer({
|
|
7
|
+
serverId: 'company-fundamentals',
|
|
8
|
+
serverName: 'official-company-fundamentals',
|
|
9
|
+
toolName: 'company_fundamentals',
|
|
10
|
+
toolDescription: 'Return fixture-mode company fundamentals with explicit source metadata.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
ticker: z.string().describe('Ticker symbol, e.g. 600519.SH or AAPL.US.'),
|
|
13
|
+
},
|
|
14
|
+
handler: ({ ticker }) => {
|
|
15
|
+
const normalizedTicker = normalizeTicker(ticker);
|
|
16
|
+
const fundamentals = FUNDAMENTAL_FIXTURES[normalizedTicker] ?? null;
|
|
17
|
+
|
|
18
|
+
if (!fundamentals) {
|
|
19
|
+
return fixtureResponse({
|
|
20
|
+
capability: 'company-fundamentals',
|
|
21
|
+
ticker: normalizedTicker,
|
|
22
|
+
found: false,
|
|
23
|
+
message: 'Ticker not found in fixture dataset.',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return fixtureResponse({
|
|
28
|
+
capability: 'company-fundamentals',
|
|
29
|
+
ticker: normalizedTicker,
|
|
30
|
+
found: true,
|
|
31
|
+
fundamentals,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "company-fundamentals",
|
|
3
|
+
"name": "Official Company Fundamentals MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "company_fundamentals", "classification": "cacheable" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "company_fundamentals",
|
|
12
|
+
"arguments": { "ticker": "AAPL.US" }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { COMPLIANCE_RULES, fixtureResponse } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
const FORBIDDEN_PATTERNS = [
|
|
7
|
+
/(买入|卖出|加仓|清仓).*(股|手|%)/u,
|
|
8
|
+
/(保本|稳赚|必赚|无风险)/u,
|
|
9
|
+
/(内幕|未公开信息|小道消息)/u,
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
await startFixtureServer({
|
|
13
|
+
serverId: 'compliance-check',
|
|
14
|
+
serverName: 'official-compliance-check',
|
|
15
|
+
toolName: 'compliance_check',
|
|
16
|
+
toolDescription: 'Run fixture-mode compliance checks for finance conversation outputs.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
statement: z.string().describe('Statement to be checked for compliance risks.'),
|
|
19
|
+
},
|
|
20
|
+
handler: ({ statement }) => {
|
|
21
|
+
const text = String(statement ?? '').trim();
|
|
22
|
+
const violations = [];
|
|
23
|
+
|
|
24
|
+
if (!text) {
|
|
25
|
+
violations.push({
|
|
26
|
+
rule_id: 'empty_statement',
|
|
27
|
+
level: 'warn',
|
|
28
|
+
message: 'Input statement is empty; no compliance conclusion can be made.',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const pattern of FORBIDDEN_PATTERNS) {
|
|
33
|
+
if (!pattern.test(text)) continue;
|
|
34
|
+
violations.push({
|
|
35
|
+
rule_id: 'high_risk_pattern_detected',
|
|
36
|
+
level: 'blocker',
|
|
37
|
+
message: `Matched forbidden pattern: ${pattern}`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return fixtureResponse({
|
|
42
|
+
capability: 'compliance-check',
|
|
43
|
+
compliant: violations.length === 0,
|
|
44
|
+
violations,
|
|
45
|
+
ruleset: COMPLIANCE_RULES,
|
|
46
|
+
checked_text_preview: text.slice(0, 280),
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "compliance-check",
|
|
3
|
+
"name": "Official Compliance Check MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "compliance_check", "classification": "mandatory" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "compliance_check",
|
|
12
|
+
"arguments": { "statement": "请直接给我买入 100 股的建议" }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { INDUSTRY_FIXTURES, fixtureResponse } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
await startFixtureServer({
|
|
7
|
+
serverId: 'industry-report',
|
|
8
|
+
serverName: 'official-industry-report',
|
|
9
|
+
toolName: 'industry_report',
|
|
10
|
+
toolDescription: 'Return fixture-mode industry outlook reports and key metrics.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
industry: z.string().describe('Industry key, e.g. semiconductors or baijiu.'),
|
|
13
|
+
},
|
|
14
|
+
handler: ({ industry }) => {
|
|
15
|
+
const normalizedIndustry = String(industry ?? '').trim().toLowerCase();
|
|
16
|
+
const report = INDUSTRY_FIXTURES[normalizedIndustry] ?? null;
|
|
17
|
+
|
|
18
|
+
if (!report) {
|
|
19
|
+
return fixtureResponse({
|
|
20
|
+
capability: 'industry-report',
|
|
21
|
+
industry: normalizedIndustry,
|
|
22
|
+
found: false,
|
|
23
|
+
available_industries: Object.keys(INDUSTRY_FIXTURES),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return fixtureResponse({
|
|
28
|
+
capability: 'industry-report',
|
|
29
|
+
industry: normalizedIndustry,
|
|
30
|
+
found: true,
|
|
31
|
+
report,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "industry-report",
|
|
3
|
+
"name": "Official Industry Report MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "industry_report", "classification": "cacheable" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "industry_report",
|
|
12
|
+
"arguments": { "industry": "semiconductors" }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { MARKET_DATA_FIXTURES, fixtureResponse, normalizeTicker } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
await startFixtureServer({
|
|
7
|
+
serverId: 'market-data-query',
|
|
8
|
+
serverName: 'official-market-data-query',
|
|
9
|
+
toolName: 'market_data_query',
|
|
10
|
+
toolDescription: 'Return fixture-mode market snapshot data with citation metadata.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
ticker: z.string().describe('Ticker symbol, e.g. 600519.SH or NVDA.US.'),
|
|
13
|
+
},
|
|
14
|
+
handler: ({ ticker }) => {
|
|
15
|
+
const normalizedTicker = normalizeTicker(ticker);
|
|
16
|
+
const snapshot = MARKET_DATA_FIXTURES[normalizedTicker] ?? null;
|
|
17
|
+
|
|
18
|
+
if (!snapshot) {
|
|
19
|
+
return fixtureResponse({
|
|
20
|
+
capability: 'market-data-query',
|
|
21
|
+
ticker: normalizedTicker,
|
|
22
|
+
found: false,
|
|
23
|
+
message: 'Ticker not found in fixture dataset.',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return fixtureResponse({
|
|
28
|
+
capability: 'market-data-query',
|
|
29
|
+
ticker: normalizedTicker,
|
|
30
|
+
found: true,
|
|
31
|
+
snapshot,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "market-data-query",
|
|
3
|
+
"name": "Official Market Data Query MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "market_data_query", "classification": "cacheable" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "market_data_query",
|
|
12
|
+
"arguments": { "ticker": "NVDA.US" }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { PORTFOLIO_FIXTURES, fixtureResponse } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
function normalizeHoldings(rawHoldings) {
|
|
7
|
+
if (!Array.isArray(rawHoldings) || rawHoldings.length === 0) {
|
|
8
|
+
return PORTFOLIO_FIXTURES.default.holdings;
|
|
9
|
+
}
|
|
10
|
+
return rawHoldings
|
|
11
|
+
.filter(item => item && typeof item === 'object')
|
|
12
|
+
.map(item => ({
|
|
13
|
+
ticker: String(item.ticker ?? '').trim(),
|
|
14
|
+
market_value: Number(item.market_value ?? item.marketValue ?? 0),
|
|
15
|
+
sector: String(item.sector ?? 'unknown').trim() || 'unknown',
|
|
16
|
+
}))
|
|
17
|
+
.filter(item => item.ticker && Number.isFinite(item.market_value) && item.market_value > 0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function buildSectorExposure(holdings, totalValue) {
|
|
21
|
+
const bySector = new Map();
|
|
22
|
+
for (const holding of holdings) {
|
|
23
|
+
const previous = bySector.get(holding.sector) ?? 0;
|
|
24
|
+
bySector.set(holding.sector, previous + holding.market_value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return [...bySector.entries()]
|
|
28
|
+
.map(([sector, value]) => ({
|
|
29
|
+
sector,
|
|
30
|
+
market_value: Number(value.toFixed(2)),
|
|
31
|
+
weight_pct: totalValue > 0 ? Number(((value / totalValue) * 100).toFixed(2)) : 0,
|
|
32
|
+
}))
|
|
33
|
+
.sort((a, b) => b.market_value - a.market_value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
await startFixtureServer({
|
|
37
|
+
serverId: 'portfolio-analysis',
|
|
38
|
+
serverName: 'official-portfolio-analysis',
|
|
39
|
+
toolName: 'portfolio_analysis',
|
|
40
|
+
toolDescription: 'Run fixture-mode portfolio concentration and sector exposure analysis.',
|
|
41
|
+
inputSchema: {
|
|
42
|
+
holdings: z.array(z.object({
|
|
43
|
+
ticker: z.string(),
|
|
44
|
+
market_value: z.number().optional(),
|
|
45
|
+
marketValue: z.number().optional(),
|
|
46
|
+
sector: z.string().optional(),
|
|
47
|
+
})).optional().describe('Optional holdings array; uses default fixture portfolio when omitted.'),
|
|
48
|
+
},
|
|
49
|
+
handler: ({ holdings }) => {
|
|
50
|
+
const normalizedHoldings = normalizeHoldings(holdings);
|
|
51
|
+
|
|
52
|
+
const totalValue = normalizedHoldings.reduce((acc, item) => acc + item.market_value, 0);
|
|
53
|
+
const sortedByValue = [...normalizedHoldings].sort((a, b) => b.market_value - a.market_value);
|
|
54
|
+
const top = sortedByValue[0] ?? null;
|
|
55
|
+
const topWeightPct = top && totalValue > 0
|
|
56
|
+
? Number(((top.market_value / totalValue) * 100).toFixed(2))
|
|
57
|
+
: 0;
|
|
58
|
+
|
|
59
|
+
return fixtureResponse({
|
|
60
|
+
capability: 'portfolio-analysis',
|
|
61
|
+
holdings_count: normalizedHoldings.length,
|
|
62
|
+
total_market_value: Number(totalValue.toFixed(2)),
|
|
63
|
+
concentration: {
|
|
64
|
+
top_holding_ticker: top?.ticker ?? null,
|
|
65
|
+
top_holding_weight_pct: topWeightPct,
|
|
66
|
+
},
|
|
67
|
+
sector_exposure: buildSectorExposure(normalizedHoldings, totalValue),
|
|
68
|
+
citation: {
|
|
69
|
+
id: 'fixture://portfolio/analysis-2026-04-20',
|
|
70
|
+
source: 'Local fixture portfolio analytics engine',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "portfolio-analysis",
|
|
3
|
+
"name": "Official Portfolio Analysis MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "portfolio_analysis", "classification": "mandatory" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "portfolio_analysis",
|
|
12
|
+
"arguments": {}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { PORTFOLIO_FIXTURES, fixtureResponse } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
await startFixtureServer({
|
|
7
|
+
serverId: 'portfolio-read',
|
|
8
|
+
serverName: 'official-portfolio-read',
|
|
9
|
+
toolName: 'portfolio_read',
|
|
10
|
+
toolDescription: 'Read fixture-mode portfolio snapshots with explicit source metadata.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
profile: z.string().optional().describe('Portfolio profile key (default: default).'),
|
|
13
|
+
},
|
|
14
|
+
handler: ({ profile = 'default' }) => {
|
|
15
|
+
const profileKey = String(profile ?? 'default').trim().toLowerCase() || 'default';
|
|
16
|
+
const snapshot = PORTFOLIO_FIXTURES[profileKey] ?? null;
|
|
17
|
+
|
|
18
|
+
if (!snapshot) {
|
|
19
|
+
return fixtureResponse({
|
|
20
|
+
capability: 'portfolio-read',
|
|
21
|
+
profile: profileKey,
|
|
22
|
+
found: false,
|
|
23
|
+
available_profiles: Object.keys(PORTFOLIO_FIXTURES),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return fixtureResponse({
|
|
28
|
+
capability: 'portfolio-read',
|
|
29
|
+
profile: profileKey,
|
|
30
|
+
found: true,
|
|
31
|
+
snapshot,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "portfolio-read",
|
|
3
|
+
"name": "Official Portfolio Read MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "portfolio_read", "classification": "mandatory" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "portfolio_read",
|
|
12
|
+
"arguments": { "profile": "default" }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { RESEARCH_FIXTURES, fixtureResponse, normalizeTicker } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
await startFixtureServer({
|
|
7
|
+
serverId: 'research-fetch',
|
|
8
|
+
serverName: 'official-research-fetch',
|
|
9
|
+
toolName: 'research_fetch',
|
|
10
|
+
toolDescription: 'Fetch fixture-mode research notes with explicit citations (non-real-time).',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
query: z.string().optional().describe('Keyword query for report filtering.'),
|
|
13
|
+
ticker: z.string().optional().describe('Ticker symbol, e.g. 600519.SH or NVDA.US.'),
|
|
14
|
+
limit: z.number().int().min(1).max(10).optional().describe('Maximum returned notes (default 3).'),
|
|
15
|
+
},
|
|
16
|
+
handler: ({ query, ticker, limit = 3 }) => {
|
|
17
|
+
const normalizedQuery = String(query ?? '').trim().toLowerCase();
|
|
18
|
+
const normalizedTicker = normalizeTicker(ticker);
|
|
19
|
+
|
|
20
|
+
const matches = RESEARCH_FIXTURES.filter((item) => {
|
|
21
|
+
if (normalizedTicker && item.ticker !== normalizedTicker) return false;
|
|
22
|
+
if (!normalizedQuery) return true;
|
|
23
|
+
const haystack = `${item.title} ${item.summary}`.toLowerCase();
|
|
24
|
+
return haystack.includes(normalizedQuery);
|
|
25
|
+
}).slice(0, limit);
|
|
26
|
+
|
|
27
|
+
return fixtureResponse({
|
|
28
|
+
capability: 'research-fetch',
|
|
29
|
+
query: normalizedQuery || null,
|
|
30
|
+
ticker: normalizedTicker || null,
|
|
31
|
+
count: matches.length,
|
|
32
|
+
notes: matches,
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "research-fetch",
|
|
3
|
+
"name": "Official Research Fetch MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "research_fetch", "classification": "cacheable" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "research_fetch",
|
|
12
|
+
"arguments": { "query": "demand", "limit": 1 }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { RISK_FIXTURES, fixtureResponse, normalizeTicker } from '../../official-common/fixtures.js';
|
|
4
|
+
import { startFixtureServer } from '../../official-common/server.js';
|
|
5
|
+
|
|
6
|
+
await startFixtureServer({
|
|
7
|
+
serverId: 'risk-metrics',
|
|
8
|
+
serverName: 'official-risk-metrics',
|
|
9
|
+
toolName: 'risk_metrics',
|
|
10
|
+
toolDescription: 'Return fixture-mode risk metrics (beta, VaR, drawdown) with citation.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
ticker: z.string().describe('Ticker symbol, e.g. NVDA.US.'),
|
|
13
|
+
},
|
|
14
|
+
handler: ({ ticker }) => {
|
|
15
|
+
const normalizedTicker = normalizeTicker(ticker);
|
|
16
|
+
const metrics = RISK_FIXTURES[normalizedTicker] ?? null;
|
|
17
|
+
|
|
18
|
+
if (!metrics) {
|
|
19
|
+
return fixtureResponse({
|
|
20
|
+
capability: 'risk-metrics',
|
|
21
|
+
ticker: normalizedTicker,
|
|
22
|
+
found: false,
|
|
23
|
+
message: 'Ticker not found in fixture dataset.',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return fixtureResponse({
|
|
28
|
+
capability: 'risk-metrics',
|
|
29
|
+
ticker: normalizedTicker,
|
|
30
|
+
found: true,
|
|
31
|
+
metrics,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "risk-metrics",
|
|
3
|
+
"name": "Official Risk Metrics MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"runtime": "node",
|
|
6
|
+
"entrypoint": "index.js",
|
|
7
|
+
"tool_declarations": [
|
|
8
|
+
{ "name": "risk_metrics", "classification": "cacheable" }
|
|
9
|
+
],
|
|
10
|
+
"smoke_test": {
|
|
11
|
+
"tool": "risk_metrics",
|
|
12
|
+
"arguments": { "ticker": "600519.SH" }
|
|
13
|
+
}
|
|
14
|
+
}
|