模拟REST API + MCP服务器/客户端 + Ollama(教程指南)
此存储库显示了一个完整的管道,LLM(通过Ollama)可以使用MCP与REST API进行通信。
实际目标:
- 具有包含实际PostgreSQL数据的REST API模拟;
- 将API操作暴露为MCP工具;
- 使用MCP客户端将工具传递给Ollama,并让模型决定何时调用它们。
这样,模型就不会发明数据:它实际上通过工具读取/写入数据库。
(1)一般架构
组件 :
REST API(Ktor):espone端点HTTP(/customers,/orders)e美国PostgreSQL。PostgreSQL实际数据的持久性。MCP Server(stdio + JSON-RPC):将 MCP 工具调用转换为 REST API 的 HTTP 调用。MCP Client:Ollama e MCP服务器的编排层。OllamaLLM接收工具列表并决定何时调用它们。
高级流量:
- 用户向 MCP 客户端发送提示符。
- 客户端与服务器(stdio)初始化 MCP 会话。
- 客户端使用可用的工具(
tools/list). - 客户端向 Ollama 发送 prompt + schema tool (
/api/chat). - Ollama可以回答
tool_calls. - 客户端运行每个工具调用 MCP (
tools/call). - MCP 服务器调用 REST API。
- REST API 读取/写入 PostgreSQL。
- 结果可以追溯到Ollama,Ollama以自然语言产生最终答案。
2)项目结构
.
├── src/main/kotlin/com/miscsvc/
│ ├── Main.kt
│ ├── api/
│ │ ├── ApiRepository.kt
│ │ ├── ApiServer.kt
│ │ ├── Models.kt
│ │ └── Validation.kt
│ ├── config/
│ │ ├── AppSettings.kt
│ │ └── EnvLoader.kt
│ ├── db/
│ │ ├── DatabaseConnections.kt
│ │ └── DbBootstrap.kt
│ ├── json/
│ │ └── JsonSupport.kt
│ └── mcp/
│ ├── client/
│ │ ├── McpClientApp.kt
│ │ └── McpStdIOClient.kt
│ ├── protocol/
│ │ └── StdioJsonRpc.kt
│ └── server/
│ └── McpServer.kt
├── scripts/
│ ├── _common.sh
│ ├── bootstrap-db.sh
│ ├── run-api.sh
│ ├── run-mcp-server.sh
│ └── run-mcp-client.sh
├── build.gradle.kts
├── settings.gradle.kts
├── .env.example
└── README.md3) 先决条件
- Java 21+
- Gradle 8+
- Docker 中的 PostgreSQL(已在您的设置中提供)
- 主机: localhost - 端口: 5432 - 用户: postgres - 密码: postgres
- 可选的 pgAdmin :
http://localhost:5050 - 正在运行的浏览器 :
http://127.0.0.1:11434
4) 配置
正在将%'d(位于“%B”中)的%'d文件复制到“%B
cp .env.example .env核心价值观:
POSTGRES_HOST=127.0.0.1POSTGRES_PORT=5432POSTGRES_USER=postgresPOSTGRES_PASSWORD=postgresPOSTGRES_DB=misc_svcPOSTGRES_ADMIN_DB=postgresAPI_HOST=0.0.0.0API_PORT=8000API_BASE_URL=http://127.0.0.1:8000OLLAMA_URL=http://127.0.0.1:11434OLLAMA_MODEL=gpt-oss:120b-cloudMCP_SERVER_COMMAND=./scripts/run-mcp-server.shMCP_SERVER_ARGS=
不重要:
- 客户端通过stdio作为子进程启动MCP服务器。
MCP_SERVER_COMMAND必须指向当前环境中有效的命令。API_BASE_URL它必须指向与 REST API 运行的端口完全相同的端口。
5) 快速设置
cd /Users/antoniolatela/Documents/mcp_trial_kotlin
cp .env.example .env
gradle -q fatJar注:
- 如果 jar 不存在,则脚本
./scripts/*.sh自动建造; - 使用
./gradlew替换gradle骗局./gradlew.
6) Bootstrap数据库(crea DB/tabelle/seed)
命令 :
./scripts/bootstrap-db.sh它做什么 src/main/kotlin/com/miscsvc/db/DbBootstrap.kt:
- Connette al数据库管理员(
postgres); - 检查是否存在
misc_svc; - 如果缺少,创造它;
- 连接到
misc_svc; - 创建表格 :
- customers(id, name, email, created_at) - orders(id, customer_id, item, amount, status, created_at)
- 插入 seed idempotent:
- 2 初始客户 - 2 初始订单
同能 :
- 您可以重新启动引导,而无需重复主种子记录。
7) 启动服务
7.1 启动 REST API
./scripts/run-api.sh有用的终端 :
GET /healthGET /customersPOST /customersGET /ordersPOST /orders
7.2 启动 MCP 服务器(可选手动)
客户端会自动启动。如果你想单独尝试:
./scripts/run-mcp-server.sh重要提示:
- stdio 上的 MCP 服务器不会打印 HTTP 横幅,可能看起来“停止”:正常;
- 使用MCP客户端时中止stdin/stdout。
7.3 使用 Ollama 启动 MCP 客户端
单个请求:
./scripts/run-mcp-client.sh "Mostrami clienti e ordini"互动模式 :
./scripts/run-mcp-client.sh7.4 飞行前检查(推荐)
在启动客户端之前,请检查模拟API是否真的响应配置的URL:
echo "$API_BASE_URL"
curl -i "$API_BASE_URL/health"
curl -i "$API_BASE_URL/customers"你必须看到:
200 OK素/health- 身体
{"status":"ok"}.
再见 404 Not Found你几乎总是在同一扇门上敲另一个服务。 在这种情况下,使用不同的端口(例如。 8010) 并调整API和 API_BASE_URL:
export API_PORT=8010
export API_BASE_URL=http://127.0.0.1:8010
./scripts/run-api.sh在第二个终端:
export API_BASE_URL=http://127.0.0.1:8010
./scripts/run-mcp-client.sh "Mostrami clienti e ordini"8) MCP客户端-服务器-API对话如何工作(详情)
序列图 :
sequenceDiagram
participant U as Utente
participant C as MCP Client
participant M as Ollama
participant S as MCP Server
participant A as REST API
participant D as PostgreSQL
U->>C: Prompt naturale
C->>S: initialize
S-->>C: capabilities + serverInfo
C->>S: tools/list
S-->>C: lista tool
C->>M: /api/chat (messages + tools)
M-->>C: tool_calls
C->>S: tools/call
S->>A: HTTP API call
A->>D: SELECT/INSERT
D-->>A: dati
A-->>S: JSON
S-->>C: tool result (content.text)
C->>M: /api/chat (tool result)
M-->>C: risposta finale
C-->>U: output testuale步骤A:MCP初始化
src/main/kotlin/com/miscsvc/mcp/client/McpStdIOClient.kt 打开一个子进程:
- 命令 :
./scripts/run-mcp-server.sh - 运输:stdio
- 协议: JSON-RPC 与框架
Content-Length.
客户发送:
- 方法:
initialize - 协议版本:
2024-11-05
服务器响应:
capabilities.toolsserverInfo.
步骤 B:工具发现
客户打电话 tools/list.
服务器以JSON模式返回工具:
health_checklist_customerscreate_customerlist_orderscreate_order
步骤 C: 工具方案 -> 其他
客户端将MCP工具转换为Ollama期望的函数调用格式,并发送:
messages(系统+用户)tools(可用功能)- 端点:
POST /api/chat
步骤D:LLM决策
Ollama可以回答:
- 直接最终文本,或
tool_calls要执行 。
步骤E:执行工具
对于每个工具调用:
- 客户端调用 MCP
tools/call; - 服务器识别工具处理器;
- 处理器对REST API进行HTTP调用;
- la REST API歌剧su PostgreSQL;
- 结果返回给客户端,如
content[type=text].
步骤F:最终答案
客户端将工具结果添加到 messages 有角色 tool 他叫Ollama。
- 如果还有其他 tool_calls,循环将继续。
- 如果没有 tool_calls,则将打印 assistant 文本作为最终输出。
实际消息示例(简化)
initialize (客户端->服务器):
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "ollama-mcp-client-kotlin", "version": "1.0.0"}
}
}tools/list 响应(服务器->客户端,estratto):
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{"name": "list_customers", "inputSchema": {"type": "object", "properties": {}}},
{"name": "create_order", "inputSchema": {"type": "object", "properties": {"customer_id": {"type": "integer"}}}}
]
}
}使用可用工具调用 Ollama (客户端 -> POST /api/chat):
{
"model": "gpt-oss:120b-cloud",
"messages": [
{"role": "system", "content": "Sei un assistente..."},
{"role": "user", "content": "Mostrami i clienti"}
],
"tools": [
{
"type": "function",
"function": {
"name": "list_customers",
"parameters": {"type": "object", "properties": {}}
}
}
],
"stream": false
}Risposta骗局 tool_calls (旧 -> 客户端, 摘录):
{
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{"id": "call_1", "function": {"name": "list_customers", "arguments": {}}}
]
}
}tools/call (客户端->服务器):
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {"name": "list_customers", "arguments": {}}
}tools/call 响应(服务器->客户端,estratto):
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\"ok\": true, \"status_code\": 200, \"data\": [...]}"
}
]
}
}9) 文件对文件的代码深化
src/main/kotlin/com/miscsvc/config/AppSettings.kt
责任:
- 加载
.env; - 集中DB/API/MCP/Ollama配置。
关键要点:
- 强大的本地开发备份;
- 解析MCP服务器命令参数;
- 主机/端口/凭据的唯一真相点。
src/main/kotlin/com/miscsvc/config/EnvLoader.kt
责任:
- 最小文件解析
.env.
选项 :
- 支持注释和空行;
- 简单且可预测的key/value解析。
src/main/kotlin/com/miscsvc/db/DatabaseConnections.kt
责任:
- 创建PostgreSQL连接(管理员和应用程序)。
选项 :
- 直接JDBC与PostgreSQL驱动程序;
- DB 管理员和应用 DB 的单独 URL。
src/main/kotlin/com/miscsvc/db/DbBootstrap.kt
责任:
- 初步配置数据库和模式。
关键功能:
createDatabaseIfMissing()如果不存在,则创建 DB。createTablesAndSeed():奶油塔贝尔+种子;bootstrapDatabase():配器大结局。
重要信息:
- DB 标识符的安全配额;
- DB限制:
UNIQUE(email)FK-suorders.customer_id,检查苏amount >= 0.
src/main/kotlin/com/miscsvc/api/Models.kt
责任:
- 定义payload request/response和域异常。
例如:
CustomerCreate(name, email)OrderCreate(customerId, item, amount, status)
src/main/kotlin/com/miscsvc/api/Validation.kt
责任:
- 验证传入的有效负载。
优势:
- 无效的输入在触摸 DB 之前被锁定。
src/main/kotlin/com/miscsvc/api/ApiRepository.kt
责任:
- 映射SQL\模型Kotlin。
行为 :
createCustomer:调解UNIQUE域例外;createOrderFK invalid -> 域异常
src/main/kotlin/com/miscsvc/api/ApiServer.kt
责任:
- HTTP端点REST e映射错误。
行为 :
- 引导一切;
POST /customers:重复电子邮件->HTTP409;POST /orders:FK无效->HTTP404.
src/main/kotlin/com/miscsvc/mcp/protocol/StdioJsonRpc.kt
责任:
- 根据JSON-RPC MCP协议构建stdio。
主要块:
- header/body 与
Content-Length; - JSON-RPC消息的序列化和写入。
src/main/kotlin/com/miscsvc/mcp/server/McpServer.kt
责任:
- 实现服务器MCP minimal su stdio。
主要块:
- MCP调度方法
- initialize - tools/list - tools/call - ping
- 注册表工具
- 定义输入模式和处理器。
- 桥接HTTP
- callApi() 将请求发送到REST API并标准化输出(ok, status_code, data|error).
src/main/kotlin/com/miscsvc/mcp/client/McpStdIOClient.kt
责任:
- 作为子进程启动 MCP 服务器;
- 管理请求/通知JSON-RPC。
曝光 :
initialize()listTools()callTool()
src/main/kotlin/com/miscsvc/mcp/client/McpClientApp.kt
责任:
- 编排LLM周期\ MCP工具。
重要部分:
- 转换工具
- 模式MCP->函数调用Ollama。
- 循环工具调用
- 邀请提示Ollama; - 执行任何 tool_calls; - 将工具结果重新发送到Ollama; - 最终文本回复到达时结束。
- 命令行界面
- 一枪(./scripts/run-mcp-client.sh "...") - 互动 (./scripts/run-mcp-client.sh).
src/main/kotlin/com/miscsvc/Main.kt
责任:
- 带子命令的唯一 entrypoint:
- bootstrap-db - api - mcp-server - mcp-client
10)直接API示例(无MCP)
创建客户:
curl -X POST http://127.0.0.1:8000/customers \
-H "Content-Type: application/json" \
-d '{"name":"Giulia Verdi","email":"giulia.verdi@example.com"}'创建订单:
curl -X POST http://127.0.0.1:8000/orders \
-H "Content-Type: application/json" \
-d '{"customer_id":1,"item":"Tastiera","amount":79.90,"status":"new"}'11) 故障排除
connection refused su PostgreSQL:
- 检查活动的 PostgreSQL 容器
localhost:5432; - 验证 凭据 在
.env.
address already in use API:
- 门
8000忙碌,改变API_PORT或者停止冲突过程。
客户回答 404 Not Found:
API_BASE_URL指向错误的服务(典型:其他应用程序):8000);- 用验证
curl "$API_BASE_URL/health"; - 移动 API 和客户端
8010(见第 7.4 节),然后再试一次。
服务器启动 MCP 错误 :
- 控制
MCP_SERVER_COMMAND在.env; - 在这个项目中,推荐的默认值和
./scripts/run-mcp-server.sh.
似乎 ./scripts/run-mcp-server.sh “非部分”:
- 等待:stdio 上的 MCP 服务器没有显示 web/HTTP 输出;
- 让进程运行或直接使用
run-mcp-client.sh让他自己开始。
奥拉马没有回答:
- 验证
ollama serve活跃; - 查看可用模型(
OLLAMA_MODEL例如gpt-oss:120b-cloud).
12) 为什么这个架构是有用的
- 明确划分角色:
- API=业务/数据层 - MCP服务器=工具暴露层 - 客户+Ollama=推理+决策工具
- 可单独测试每个级别;
- 防止模型直接访问 DB;
- 方便未来的扩展:只需添加endpoint + tool。
(3)可能的扩展
- 将 auth 添加到 REST API
- 添加结构化日志和跟踪工具调用;
- 添加自动测试(单元+集成);
- 添加新的工具(更新/删除,过滤器,分页);
- 支持MCP传输替代方案(如流式HTTP)。
