印度金融MCP服务器
一个MCP服务器,通过OAuth 2.1和基于角色的层提供对印度金融数据(NSE、BSE、共同基金、新闻、宏观)的统一访问。
堆栈
- 运行时间: Node.js 18+、TypeScript、Fastify
- MCP:
@modelcontextprotocol/sdk(流式HTTP,有状态会话) - 基础设施(Docker): Keycloak 26、PostgreSQL 16、Redis 7
第0天设置
- 克隆仓库。
- 复制
.env.example到.env在回购根(用于Compose变量替换),并根据需要填写API键。 - 从repo根目录:
docker compose up --build. - 配置Keycloak(开发):
- 打开 http://localhost:8080 并使用登录 管理员 / 管理员 (引导管理员从 KC_BOOTSTRAP_ADMIN_*). - 创建领域 finance. - 创建公共客户端 mcp-client 启用了PKCE(用于以后的OAuth流)。
- 验证API:
- curl -s http://localhost:3000/health → {"status":"ok"} - 可选: curl -s http://localhost:3000/.well-known/oauth-protected-resource 用于OAuth资源元数据。
本地开发(Node应用程序不使用Docker)
npm install --prefix server
cp .env.example server/.env # optional; dotenv loads from cwd
npm run dev --prefix server数据库注释
PostgreSQL用数据库初始化 keycloak (适用于Keycloak)和 mcp_data (适用于应用程序),通过 scripts/init-mcp-db.sqlMCP容器使用 DATABASE_URL=postgresql://keycloak:keycloak@postgres:5432/mcp_data.
MCP端点
- 发布/获取/删除
/mcp--带有会话头的流式HTTPmcp-session-id初始化后(请参阅MCP Streamable HTTP规范和@modelcontextprotocol/sdk示例)。 需要承载访问令牌 在所有/mcp电话(第1天)。
第1天:OAuth、层和NSE报价
钥匙锁
- 领域
finance,客户mcp-client(根据需要,公开PKCE)。 - 启用 直接访问授权 上
mcp-client如果你使用scripts/get-token.sh(仅限dev)。 - 领域角色:
free,premium,analyst--分配给测试用户(例如。free@example.com, …). - 确保 领域角色出现在访问令牌中 (客户范围+ *领域角色* 映射器,或默认值
roles范围)。 - 受众/授权方:令牌应包括
azp=mcp-client和aud包含mcp-client(添加一个 观众 如果需要,可以在Keycloak中使用映射器)。
环境
看 .env.example: AUTH_SERVER_URL (必须与JWT匹配 iss),可选 KEYCLOAK_INTERNAL_URL 当MCP容器从以下位置获取JWKS时 http://keycloak:8080/... 但代币使用 http://localhost:8080/...,加 PUBLIC_BASE_URL, OAUTH_CLIENT_ID.
工具
get_stock_quote--NSE股权报价stock-nse-india(thenseindia简报中的npm名称未发布;这个图书馆提供NseIndia).报价缓存在 瑞迪斯 (60秒TTL);在上游故障时,缓存值在可用时返回。- Tier → 合成的 范围 源自于
realm_access.roles在server/src/auth/tiers.ts.中间件需要market:read对于任何/mcp交通;报价工具通过MCP检查相同的范围authInfo.
开发者令牌
./scripts/get-token.sh free@example.com 'user-password'为什么显示光标 invalid_union /JSON-RPC错误
MCP客户端只理解 JSON-RPC 2.0 身体。其他任何内容(例如Fastify的默认设置) 404 JSON,或 { "error": "missing_token" } 关于飞行前的选项)被验证为JSON-RPC并失败。
此服务器现在:
- 跳过熊认证
OPTIONS和HEAD上/mcp(CORS飞行前)。 - 寄存器 跨域资源共享 (
@fastify/cors)用于浏览器/Electron OAuth流。 - 退货 JSON RPC形状错误 对于坏 获取/删除 会话案例。
- 供应 RFC 9728–样式 元数据在
/.well-known/oauth-protected-resource(包括resource,authorization_servers,jwks_uri,openid_configuration).
游标:OAuth与静态 Authorization 头球
- OAuth(
auth在mcp.json):Cursor负责打开登录页面、交换代码和附加Authorization: Bearer …MCP HTTP请求。该行为在 光标,不在这个回购中。同样的模式也适用于 身份验证0, 钥匙锁,或任何OIDC提供商,只要发行者/JWKS和客户端设置匹配。 - 不要 混合长寿命
headers.Authorization进入与auth除非你知道Cursor的合并规则;更喜欢 一 方法。无秘密示例:docs/cursor-mcp.example.json.
如果您之前将JWT粘贴到 mcp.json, 旋转 Keycloak中的用户会话或客户端密钥,并仅使用OAuth或短期开发令牌。
如何调用此MCP
- 光标 --在中添加服务器
mcp.json(参见示例),启动Docker/npm start,重新加载MCP;在提示时完成OAuth。 - curl/脚本 --获取令牌(
scripts/get-token.sh),然后发送Authorization: Bearer在每一个 发布/获取/删除 到/mcp(流式HTTP+mcp-session-id初始化后)。 - 其他MCP客户端 --将HTTP传输指向
http://localhost:3000/mcp并使用配置OIDC/.well-known/oauth-protected-resource.
在游标中使用此MCP(逐步)
- 开始一切 (回购根):
docker compose up --build--等到mcp-serverKeycloak、Postgres和Redis都已启动。检查:curl -s http://localhost:3000/health. - 钥匙锁 (一次性):领域
finance,公共客户mcp-client,有效 重定向URI 对于Cursor的OAuth回调, 直接访问授权 如果你使用scripts/get-token.sh,具有领域角色的用户free/premium/analyst. - 光标配置 --合并
docs/cursor-mcp.example.json进入~/.cursor/mcp.json那么 重新加载MCP (命令选项板→ MCP:重新加载/重新启动光标)。 - OAuth流程 --光标打开Keycloak(或显示登录步骤),您登录;游标存储令牌并发送
Authorization: Bearer …在每个/mcp请求。然后 初始化 通过Streamable HTTP运行(稍后请求的标头中的会话id)。 - 聊天中 --使用以下工具
ping或get_stock_quote当主持人列出它们时;您不会将JWT粘贴到提示中。
如果日志仍然显示 invalid_union
这意味着游标已解析 JSON不是JSON-RPC 2.0 (例如OAuth错误体、Fastify 404 JSON或非-data: SSE线)。如果你也看到 “正在恢复…成功列出产品后连接”,客户经常 恢复 工具仍然有效。
我们修好了 Method not found 为了 prompts / resources:用于做广告的服务器 prompts 和 resources 未实施 prompts/list 或 resources/list。它现在做广告 仅限工具 (server/src/mcp/serverFactory.ts). 重建 拉动更改后: docker compose up --build.
Docker说明
套 AUTH_SERVER_URL 到 公共 发行人(http://localhost:8080/realms/finance)以及 KEYCLOAK_INTERNAL_URL 到 http://keycloak:8080/realms/finance 所以JWKS是从内部工作的 mcp-server 集装箱。
项目布局
server/--MCP HTTP服务器docs/architecture.md--架构(占位符)scripts/keycloak-setup.sh--自动化占位符
