数据服务器+MCP服务器部署MCP供Workbuddy调用

发布时间:2026/9/14 13:14:50

数据服务器+MCP服务器部署MCP供Workbuddy调用 需求分析公司希望用Workbuddy连接即有的数据供用户通过对话模式得到报表等数据。即有资源分析Workbuddy购买了企业版安全性有一定保障且能得到官方的支持。源头系统的数据服务器不对外全部部署在内网环境且数据需要严格控制不能让AI工具随意获取数据。现有服务器有空余资源可以在不新购服务器的情况下部署MCP服务。内部人力众所周知ALL IN 1系统架构架构图数据服务器新增用户、密码赋予查询某个表的权限MCP服务器服务器配置白名单加入MCP服务的对外端口选择自己的技术栈部署MCP服务这里举例用python来进行MCP服务部署python安装mcp包以及其他依赖包pycharm同时安装AI工具通过AI进行初步的代码生成历经超过30次的调试MCP服务调通最终的示例代码如下#codingutf-8importasyncioimportloggingimportoracledbfromtypingimportAny,Dict,Listfrommcp.serverimportServerfrommcp.typesimportTool,TextContentfromstarlette.applicationsimportStarlettefromstarlette.routingimportRoutefromstarlette.requestsimportRequestfromstarlette.responsesimportResponsefrommcp.server.sseimportSseServerTransportimportuvicornimportos# 配置日志logging.basicConfig(levellogging.INFO)loggerlogging.getLogger(MCP-Oracle-Server)# 环境变量读取注意这里配置环境变量更安全hostos.environ.get(host,localhost)portint(os.environ.get(port,))oracleuseros.environ.get(oracleuser,)oraclepasswordos.environ.get(oraclepassword,)service_nameos.environ.get(service_name,)# 启动前校验避免带空配置运行ifnotall([oracleuser,oraclepassword,service_name]):logger.warning(⚠️ Missing required environment variables (oracleuser, oraclepassword, service_name). Server may fail to connect.)# 数据库配置DB_CONFIG{host:host,port:port,service_name:service_name,user:oracleuser,password:oraclepassword}# 初始化 MCP ServerappServer(oracle-data-connector)# 白名单ALLOWED_TABLES{实例.表名:[X,XX,XXX,XXXX]}# 全局连接池poolNonedefinit_oracle_client():初始化 Oracle Thick 模式try:# 使用客户端路径client_dirr有效路径oracledb.init_oracle_client(lib_dirclient_dir)logger.info(f✅ Oracle Thick mode initialized successfully using client:{client_dir})exceptExceptionase:logger.error(f❌ Failed to initialize Oracle Thick mode:{e})raisedefinit_connection_pool():初始化 Oracle 连接池提升查询性能globalpoolifpoolisNone:try:dsnf{DB_CONFIG[host]}:{DB_CONFIG[port]}/{DB_CONFIG[service_name]}pooloracledb.create_pool(userDB_CONFIG[user],passwordDB_CONFIG[password],dsndsn,min1,max4,increment1,getmodeoracledb.POOL_GETMODE_WAIT)logger.info(✅ Oracle Connection Pool initialized successfully.)exceptExceptionase:logger.error(f❌ Failed to initialize Oracle Connection Pool:{e})raisedefget_db_connection():从连接池获取连接ifpoolisNone:init_connection_pool()returnpool.acquire()app.list_tools()asyncdeflist_tools()-List[Tool]:return[Tool(namelist_allowed_tables,description列出当前 MCP 服务允许查询的所有表名,inputSchema{type:object,properties:{},required:[]}),Tool(namequery_oracle_table,description查询指定 Oracle 表的数据。仅支持预定义白名单中的表和列。,inputSchema{type:object,properties:{table_name:{type:string,description:要查询的表名必须在大写白名单中},columns:{type:array,items:{type:string},description:要查询的列名列表。如果为空或包含*则返回所有允许列。},limit:{type:integer,description:限制返回行数默认 10最大 100,default:10},filter_column:{type:string,description:可选用于过滤的列名},filter_value:{type:string,description:可选过滤值}},required:[table_name]})]app.call_tool()asyncdefcall_tool(name:str,arguments:Dict[str,Any])-List[TextContent]:try:ifnamelist_allowed_tables:tableslist(ALLOWED_TABLES.keys())return[TextContent(typetext,textfAllowed tables:{, .join(tables)})]elifnamequery_oracle_table:table_namearguments.get(table_name,).upper()requested_columnsarguments.get(columns,[])limitmin(arguments.get(limit,10),100)filter_colarguments.get(filter_column)filter_valarguments.get(filter_value)iftable_namenotinALLOWED_TABLES:return[TextContent(typetext,textfError: Table {table_name} is not allowed.)]allowed_colsALLOWED_TABLES[table_name]ifnotrequested_columnsor*inrequested_columns:select_colsallowed_colselse:invalid_cols[colforcolinrequested_columnsifcol.upper()notinallowed_cols]ifinvalid_cols:return[TextContent(typetext,textfError: Columns{invalid_cols}are not allowed.)]select_cols[col.upper()forcolinrequested_columns]col_str, .join(select_cols)# 修复使用字典传参更安全可靠params{}base_sqlfSELECT{col_str}FROM{table_name}iffilter_colandfilter_valisnotNone:iffilter_col.upper()notinallowed_cols:return[TextContent(typetext,textfError: Filter column {filter_col} is not allowed.)]base_sqlf WHERE{filter_col.upper()} :bind_valparams[:bind_val]filter_val# Oracle 11g 兼容写法sqlfSELECT * FROM ({base_sql}) WHERE ROWNUM {limit}connget_db_connection()cursorconn.cursor()try:cursor.execute(sql,params)columns[desc[0]fordescincursor.description]rowscursor.fetchall()result_textfQuery Result for{table_name}:\nresult_text| | .join(columns) |\nresult_text||.join([---for_incolumns])|\nforrowinrows:formatted_row[str(item)ifitemisnotNoneelseNULLforiteminrow]result_text| | .join(formatted_row) |\nreturn[TextContent(typetext,textresult_text)]finally:# 无论是否报错必须关闭游标并将连接归还连接池cursor.close()conn.close()else:return[TextContent(typetext,textfUnknown tool:{name})]exceptExceptionase:logger.error(fError executing tool{name}:{e})return[TextContent(typetext,textfError:{str(e)})]defmain():# 1. 强制启用 Thick 模式并指定路径init_oracle_client()# 2. 初始化连接池try:init_connection_pool()exceptException:logger.error(❌ Database connection pool failed to initialize. MCP Server will not start.)returnsseSseServerTransport(/messages/)asyncdefhandle_sse(request:Request):asyncwithsse.connect_sse(request.scope,request.receive,request._send)as(read_stream,write_stream):awaitapp.run(read_stream,write_stream,app.create_initialization_options())asyncdefhandle_messages(request:Request):awaitsse.handle_post_message(request.scope,request.receive,request._send)returnResponse(status_code200)starlette_appStarlette(debugTrue,routes[Route(/sse,endpointhandle_sse),Route(/messages/,endpointhandle_messages,methods[POST]),Route(/messages,endpointhandle_messages,methods[POST]),],)logger.info( Starting Oracle MCP Server on port 白名单端口号...)uvicorn.run(starlette_app,host0.0.0.0,port白名单端口号)if__name____main__:main()Workbuddy端操作路径截图MCP配置代码{mcpServers:{Oracle-Connector:{transport:sse,url:http://地址:端口/sse,disabled:false}}}结论通过上述案例可以将系统的数据放在内网通过物理网络数据库单独账号控制权限同时MCP服务器单独部署也进一步杜绝了网络安全问题以及AI查数据不可控的情况。
延伸阅读

更多相关文章

2026/9/14 20:23:50

【单片机毕业设计推荐】基于 STM32 单片机的智能鱼缸环境监控与自动控制系统设计,基于 STM32 的水族箱多参数监测与自动化养护系统设计(012304)

文章目录20 个相关毕业设计备选题目项目研究背景摘要总体方案核心功能技术路线项目演示关于我们项目案例源码获取温馨提示:本人主页置顶文章(点我)有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)有 CSDN 平台官…

2026/9/13 22:44:23

Postman Mock Server实战:契约驱动开发与前后端高效协作

1. 项目概述:为什么我们需要一个“假”后端? 在前后端分离的开发模式下,一个经典的矛盾总是反复上演:前端页面已经画好了,交互逻辑也写得差不多了,但后端接口文档还躺在产品经理的脑子里,或者后…

2026/9/13 22:19:04

C++编程实战:从快递费计算项目掌握输入验证与模块化设计

1. 项目概述:从“Hello World”到解决实际问题很多朋友学C,卡在了一个尴尬的阶段:语法书看完了,cout、if-else、for循环都认识了,甚至能写个小程序算算斐波那契数列。但一遇到稍微具体点的需求,比如“根据快…

2026/9/14 20:25:27

用FastAPI-MCP搭起分布式MCP网关:从单进程到多节点

用FastAPI-MCP搭起分布式MCP网关:从单进程到多节点 【免费下载链接】fastapi_mcp Expose your FastAPI endpoints as Model Context Protocol (MCP) tools, with Auth! 项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi_mcp 假设业务团队要求把一套…

2026/9/14 20:25:27

磷酸化蛋白WB实验失败原因与优化方案

1. 磷酸化蛋白WB实验失败原因深度解析Western Blot(WB)作为蛋白质研究中最常用的技术手段之一,在磷酸化蛋白检测领域却让无数科研人员屡屡碰壁。为什么常规蛋白WB能做出来,一到磷酸化蛋白就频频失败?根据我十年蛋白实验…

2026/9/14 20:25:27

Python基础作业解析:从语法到实战应用

1. Python作业解析:从基础语法到实战应用作为一门广泛应用于各个领域的编程语言,Python以其简洁的语法和强大的功能深受开发者喜爱。这次我们将深入探讨Python基础作业中的三个核心题目,通过实际案例帮助初学者掌握关键编程概念。提示&#x…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码