SPB Git forge

spb/hfmarketdata

Public

Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)

127commits 1branches 0releases
24.7 MBsize
maindefault branch
11 days agolast push
JavaScript 53.7% Python 38.3% CSS 4.6% TypeScript 3.1%
3.6 KB · 78 lines typescript
Raw Blame History
1/**2 * Assemble the MCP server: 14 tools, 2 resources, 3 prompts, on top of an `HfmdClient`.3 * Exported so that it can be embedded (tests use an in-memory transport).4 */5import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';6import type { CallToolResult, GetPromptResult } from '@modelcontextprotocol/sdk/types.js';7import { HfmdClient, type ClientOptions } from './client.js';8import { PROMPTS } from './prompts.js';9import { RESOURCES } from './resources.js';10import { TOOLS, runTool, type ToolContext } from './tools.js';1112export const SERVER_NAME = 'hfmarketdata';13export const SERVER_VERSION = '1.0.0';1415export interface ServerOptions extends ClientOptions {16  client?: HfmdClient;17  toolContext?: ToolContext;18}1920export function createServer(opts: ServerOptions = {}): { server: McpServer; client: HfmdClient } {21  const client = opts.client ?? new HfmdClient(opts);22  const server = new McpServer(23    { name: SERVER_NAME, version: SERVER_VERSION },24    {25      instructions: [26        'HF Market Data: open high-frequency market data (stocks, ETFs, futures, crypto, indices, FX at 1-minute to daily since ~2007/2010; options chains with Greeks since 2010; SEC fundamentals point-in-time).',27        'Use search_symbols to resolve symbols, get_bars for prices, the futures tools for contracts/curves/continuous series, and the fundamentals tools for statements, ratios, screens and filings.',28        'Outputs are compact tables ({columns, rows}); results above 200 rows are summarised — narrow the range or lower `limit` to see everything.',29        client.keyless30          ? 'Running keyless (low hourly limits: 30 requests/hour per IP). Set HFMD_API_KEY for 120 requests/minute — the API key is free (account at https://www.hfmarketdata.io/signup); higher limits are granted on request by e-mail to contact@spboucher.ai, also free.'31          : 'A free API key is configured (120 requests/minute; higher limits on request by e-mail to contact@spboucher.ai, also free).',32        'Intraday timestamps are naive US/Eastern; daily bars are dates. Missing values are null — never invent data.',33      ].join(' '),34    },35  );3637  for (const t of TOOLS) {38    server.registerTool(39      t.name,40      {41        title: t.title,42        description: t.description,43        inputSchema: t.schema,44        annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: t.name !== 'subscribe_filings', openWorldHint: true },45      },46      async (args: unknown): Promise<CallToolResult> => {47        const { text, isError } = await runTool(t.name, client, args, opts.toolContext);48        return { content: [{ type: 'text', text }], isError: isError || undefined };49      },50    );51  }5253  for (const r of RESOURCES) {54    server.registerResource(r.name, r.uri, { title: r.title, description: r.description, mimeType: r.mimeType }, async (uri) => {55      let text: string;56      try {57        text = await r.read(client);58      } catch (e) {59        text = JSON.stringify({ error: e instanceof Error ? e.message : String(e) });60      }61      return { contents: [{ uri: uri.href, mimeType: r.mimeType, text }] };62    });63  }6465  for (const p of PROMPTS) {66    server.registerPrompt(p.name, { title: p.title, description: p.description, argsSchema: p.args }, (args: Record<string, unknown>): GetPromptResult => ({67      messages: [{ role: 'user' as const, content: { type: 'text' as const, text: p.build(args as never) } }],68    }));69  }7071  return { server, client };72}7374export { HfmdClient, HfmdError } from './client.js';75export { TOOLS, TOOL_NAMES, runTool } from './tools.js';76export { RESOURCES } from './resources.js';77export { PROMPTS } from './prompts.js';78