{"_id":"@bluebossa63/mcp-stock-analyzer","name":"@bluebossa63/mcp-stock-analyzer","dist-tags":{"latest":"0.0.8"},"versions":{"0.0.8":{"name":"@bluebossa63/mcp-stock-analyzer","version":"0.0.8","repository":{"type":"git","url":"git+https://github.com/bluebossa63/mcp-stock-analyzer.git"},"type":"module","bin":{"mcp-stock-analyzer":"dist/cli.js"},"scripts":{"build":"tsc -p tsconfig.json","start:stdio":"node dist/cli.js","start":"npm run start:stdio"},"dependencies":{"@modelcontextprotocol/sdk":"^0.6.0"},"devDependencies":{"typescript":"^5.5.4","@types/node":"^20.12.12"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"engines":{"node":">=20"},"_id":"@bluebossa63/mcp-stock-analyzer@0.0.8","gitHead":"d697f2ba7356b69fcfa422de51bdacb1e25699c1","description":"An **MCP server** (Node 20+) exposing stock-analysis tools.","bugs":{"url":"https://github.com/bluebossa63/mcp-stock-analyzer/issues"},"homepage":"https://github.com/bluebossa63/mcp-stock-analyzer#readme","_nodeVersion":"20.19.5","_npmVersion":"10.8.2","dist":{"integrity":"sha512-bE9ztCRek8789S1np9dKKNsDQNtvr7worRsh3b8jBEWq3YK3YyN3F0Y3/WT2Tac8goBGHqJ1EnPFFjU+HLUhxg==","shasum":"d4442ab9d0f596d2487084a2ed33a2cadcc53007","tarball":"https://registry.npmjs.org/@bluebossa63/mcp-stock-analyzer/-/mcp-stock-analyzer-0.0.8.tgz","fileCount":22,"unpackedSize":61583,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bluebossa63%2fmcp-stock-analyzer@0.0.8","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDVAGzou0B9RKBufLkHExHjcuOaasETbnV38h3M27FG/wIgbUKhgMIRSHaTk+tALMG898jfVpeBI8pQohGmBECPpH8="}]},"_npmUser":{"name":"bluebossa63","email":"daniele.ulrich@niceneasy.ch"},"directories":{},"maintainers":[{"name":"bluebossa63","email":"daniele.ulrich@niceneasy.ch"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-stock-analyzer_0.0.8_1760295128419_0.16993194601055506"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-12T18:52:08.343Z","0.0.8":"2025-10-12T18:52:08.607Z","modified":"2025-10-12T18:52:09.082Z"},"maintainers":[{"name":"bluebossa63","email":"daniele.ulrich@niceneasy.ch"}],"description":"An **MCP server** (Node 20+) exposing stock-analysis tools.","homepage":"https://github.com/bluebossa63/mcp-stock-analyzer#readme","repository":{"type":"git","url":"git+https://github.com/bluebossa63/mcp-stock-analyzer.git"},"bugs":{"url":"https://github.com/bluebossa63/mcp-stock-analyzer/issues"},"readme":"# mcp-stock-analyzer-ts (STDIO)\n\nAn **MCP server** (Node 20+) exposing stock-analysis tools.\n\nDesign goals:\n- **AI-only evaluation** – the LLM evaluates merged **time series + sentiment** (no local SMA math).\n- **N8N-friendly** – single-var env hydration, clean JSON I/O.\n- **Executable code demo** – optional tools to **POST** results to an n8n webhook.\n\n> Transport: **STDIO** (for n8n’s MCP Client node). Runtime: Node ≥20, TypeScript, pure ESM (NodeNext).\n\n## Quick start\n```bash\nnpm ci\nnpm run build\nnpx -y @bluebossa63/mcp-stock-analyzer-ts-stdio\n```\n\n## Environment setup (single-var friendly)\n\nUse exactly one:\n- `MCP_ENV=OPENAI_BASE_URL=https://api.openai.com,OPENAI_API_KEY=sk-...,OPENAI_MODEL=gpt-4o-mini`\n- `MCP_ENV_JSON={\"OPENAI_BASE_URL\":\"https://api.openai.com\",\"OPENAI_API_KEY\":\"sk-...\",\"OPENAI_MODEL\":\"gpt-4o-mini\"}`\n- `MCP_ENV_B64` = base64 of:\n  ```\n  OPENAI_BASE_URL=https://api.openai.com\n  OPENAI_API_KEY=sk-...\n  OPENAI_MODEL=gpt-4o-mini\n  ```\n\nOptional:\n- `N8N_WEBHOOK_URL` and `N8N_AUTH_HEADER` (e.g., `x-api-key: abc123`).\n\n## Tool catalog\n\nAll outputs are text JSON in `result.content[0].text`.\n\n### fetchChart\n**Input** `{ \"symbol\":\"AAPL\", \"range\":\"1mo\", \"interval\":\"1d\" }`  \n**Output** `{ \"symbol\":\"AAPL\",\"currency\":\"USD\",\"points\":[{\"t\":..., \"o\":...,\"h\":...,\"l\":...,\"c\":...,\"v\":...}] }`\n\n### fetchMultiIntraday\n**Input** `{ \"symbol\":\"NVDA\" }`  \n**Output**\n```json\n{\n  \"symbol\":\"NVDA\",\n  \"intraday\": {\n    \"1m\":  { \"points\":[...] },   // 1d/1m\n    \"15m\": { \"points\":[...] },   // 5d/15m\n    \"60m\": { \"points\":[...] }    // 1mo/60m\n  }\n}\n```\n\n### fetchNewsTitles\n**Input** `{ \"symbol\":\"NVDA\", \"max\": 10 }` → `{ \"symbol\":\"NVDA\", \"titles\":[...] }`\n\n### defineSentiment\n**Input**\n```json\n{ \"articles\": [\"Beats expectations\", \"Analyst warns of volatility\"] }\n```\n**Output**\n```json\n{ \"sentiment\":\"positive\",\"confidence\":0.78,\"reasoning\":\"...\" }\n```\n\n### evaluateWithAI / evaluateScoreWithAI\n**Input**\n```json\n{\n  \"symbol\":\"NVDA\",\n  \"intraday\": {\n    \"1m\":  { \"points\":[{\"t\":1710000000000,\"c\":100},{\"t\":1710000600000,\"c\":101}] },\n    \"15m\": { \"points\":[/* ... */] },\n    \"60m\": { \"points\":[/* ... */] }\n  },\n  \"sentiment\": { \"sentiment\":\"positive\",\"confidence\": 0.7, \"reasoning\":\"...\" },\n  \"aggregate\": false,\n  \"perTimeframeMaxPoints\": 200,\n  \"extraNotes\": \"Be conservative.\"\n}\n```\n**Output**\n```json\n{ \"perTimeframe\": { \"1m\": {\"decision\":\"hold\",\"reasoning\":\"...\"}, \"15m\": {\"decision\":\"buy\",\"reasoning\":\"...\"}, \"60m\": {\"decision\":\"hold\",\"reasoning\":\"...\"} } }\n```\n\n### getSentimentFromNews\n**Input** `{ \"symbol\":\"NVDA\", \"max\": 10 }` → `{ \"symbol\":\"NVDA\", \"titles\":[...], \"sentiment\": {...} }`\n\n### pipelineEvaluateAI\n**Input** `{ \"symbol\":\"NVDA\", \"maxNews\":10, \"aggregate\":false, \"perTimeframeMaxPoints\":200 }` → same output as `evaluateWithAI`.\n\n### postToN8N (executable)\n**Input** `{ \"payload\": {...}, \"webhookUrl\":\"https://your/webhook\", \"authHeader\":\"x-api-key: abc123\" }`  \n**Output** `{ \"ok\": true, \"status\": 200, \"statusText\": \"OK\", \"body\": \"...\" }`  \n(Env fallback: `N8N_WEBHOOK_URL`, `N8N_AUTH_HEADER`)\n\n### evaluateAndPost (executable)\nRuns `evaluateScoreWithAI` then POSTs the result.  \n**Input** = `evaluateScoreWithAI` args + optional `webhookUrl`.\n\n## Local smoke tests\n\nSentiment:\n```bash\nOPENAI_BASE_URL=https://api.openai.com OPENAI_API_KEY=sk-... OPENAI_MODEL=gpt-4o-mini node --input-type=module -e \"import('./dist/ai.js').then(async m => { const r = await m.defineSentimentFromTexts(['Strong demand','Macro risks']); console.log(r) })\"\n```\n\nEvaluate:\n```bash\nOPENAI_BASE_URL=https://api.openai.com OPENAI_API_KEY=sk-... OPENAI_MODEL=gpt-4o-mini node --input-type=module -e \"import('./dist/ai.js').then(async m => {\n  const res = await m.evaluateWithAI({\n    symbol:'NVDA',\n    intraday: { '60m': { points: [ {t:1710000000000,c:100},{t:1710003600000,c:102},{t:1710007200000,c:101} ] } },\n    sentiment: { sentiment:'neutral', confidence:0.55 },\n    aggregate:false, perTimeframeMaxPoints:120\n  });\n  console.log(JSON.stringify(res,null,2));\n})\"\n```\n\n## n8n wiring patterns\n\n**Modular** → fetchNewsTitles → defineSentiment → fetchMultiIntraday → evaluateScoreWithAI → *(optional)* postToN8N  \nHelper function to build `toolParameters`:\n```js\nfunction parseMcp(item){const raw=item?.json?.result?.content?.[0]?.text;return raw?JSON.parse(raw):null;}\nconst intradayObj = parseMcp(itemsFromNode('MCP: fetchMultiIntraday')[0]).intraday;\nconst sentimentObj = parseMcp(itemsFromNode('MCP: defineSentiment')[0]);\nconst symbol = parseMcp(itemsFromNode('MCP: fetchMultiIntraday')[0]).symbol || \"NVDA\";\nreturn [{ json: { toolParameters: JSON.stringify({ symbol, intraday: intradayObj, sentiment: sentimentObj, aggregate:false, perTimeframeMaxPoints:200 }) } }];\n```\n\n**One-shot** → pipelineEvaluateAI → *(optional)* postToN8N  \n**All-in-one** → evaluateAndPost\n\n## Yahoo ranges/intervals that work\n- `1d`  → `1m`\n- `5d`  → **`15m`** (use 15m, not 10m)\n- `1mo` → `60m`\n- `3mo+` → `1d` / `1wk` / `1mo`\n\n## Troubleshooting\n- `fetch failed` → add selectively:\n  - `NODE_OPTIONS=--dns-result-order=ipv4first`\n  - corporate proxies: `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY`\n  - corp CA: `NODE_EXTRA_CA_CERTS=/path/to/ca.pem`\n- 401 (OpenAI) → missing/garbled key; check with `debug-echo-openai`.\n- Env parsing → prefer `MCP_ENV_JSON` or `MCP_ENV_B64` if your host mangles spaces.\n\n## Version & CI publishing\n- Server version can be synced from `package.json` via JSON import: `import pkgJson from \"../package.json\" with { type: \"json\" }`.\n- See `.github/workflows/publish.yml` for tag-based publishing to npm.\n","readmeFilename":"README.md","_rev":"1-5f03d305274dea0fd655f9356d9f7306"}