@seaxlab/znlh-mcp 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.DEV.md ADDED
@@ -0,0 +1,86 @@
1
+ # README
2
+
3
+ ## 命令
4
+
5
+ ```bash
6
+ # 构建
7
+ npm run build
8
+ # 生产发布
9
+ npm run build:release
10
+ npm publish access public
11
+
12
+ # 发布到 beta 标签,避免默认 latest 被指向测试版
13
+ npm publish --tag beta
14
+
15
+ # 取消发布
16
+ npm unpublish @xxx/xx --force
17
+
18
+ ```
19
+
20
+ ## 使用 MCP Inspector 调试
21
+
22
+ [MCP Inspector](https://github.com/modelcontextprotocol/inspector) 是官方提供的调试工具:在浏览器里查看 **tools 列表**、填写参数试调、查看返回结果,适合验证 `src/tool/` 里注册的接口是否正常。
23
+
24
+ 在项目根目录执行(脚本会先 `npm run build`,再启动 Inspector 并拉起本仓库的 `node dist/index.js`):
25
+
26
+ ```bash
27
+ npm run inspector
28
+ ```
29
+
30
+ 或直接执行脚本:
31
+
32
+ ```bash
33
+ ./scripts/mcp-inspector.sh
34
+ ```
35
+
36
+ 需要为下游 HTTP 传入环境变量时,使用 Inspector 支持的 `-e`(可多次),参数会传给 `@modelcontextprotocol/inspector`,再启动本服务:
37
+
38
+ ```bash
39
+ ./scripts/mcp-inspector.sh -e BASE_URL=https://your-api.example.com -e TOKEN=your-token
40
+ ```
41
+
42
+ 终端会提示本地访问地址(常见为 `http://localhost:6274`,以实际输出为准)。首次运行会通过 `npx` 下载 Inspector,需能访问 npm registry。
43
+
44
+
45
+ ## 在 Cursor 中配置
46
+
47
+ 在 MCP 配置里增加类似项(路径请改为你本机仓库目录):
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "znlh-mcp": {
53
+ "command": "node",
54
+ "args": ["/绝对路径/znlh-mcp/dist/index.js"],
55
+ "cwd": "/绝对路径/znlh-mcp",
56
+ "env": {
57
+ "BASE_URL": "https://your-api.example.com",
58
+ "TOKEN": "your-token",
59
+ "X_AUTH_APPID": "10004"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ 开发阶段也可用 `tsx` 直接跑源码:
67
+
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "znlh-mcp-dev": {
72
+ "command": "npx",
73
+ "args": ["tsx", "/绝对路径/znlh-mcp/src/index.ts"],
74
+ "cwd": "/绝对路径/znlh-mcp",
75
+ "env": {
76
+ "BASE_URL": "https://your-api.example.com",
77
+ "TOKEN": "your-token",
78
+ "X_AUTH_APPID": "10004"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ - 新增工具可在 `src/tool/` 中实现,并在 `src/tool/register.ts` 注册;
86
+ - 下游请求可复用 `createHttpClient`(`src/http-client.ts`)。
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # znlh-mcp
2
+
3
+ 基于 Node.js 与 [@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk) 的 MCP 服务端模板,使用 **stdio** 与客户端通信。
4
+
5
+ ## 要求
6
+
7
+ - Node.js 18+
8
+
9
+ ## 配置(环境变量)
10
+
11
+ | 变量 | 说明 |
12
+ |------|------|
13
+ | `BASE_URL` | 下游接口基准地址(须含协议)。 |
14
+ | `TOKEN` | 访问令牌;若设置,HTTP 请求会带请求头 `x-auth-token` |
15
+ | `X_AUTH_APPID` | 应用 ID,请求头 `x-auth-appid` |
16
+ | `MCP_HTTP_DEBUG` | 默认开启:向 **stderr** 打印每次 HTTP 的 method、完整 URL、headers(`x-auth-token` 等会脱敏)、请求体、响应 status 与 body。设为 `0`、`false`、`off` 可关闭。不使用 stdout,避免破坏 MCP stdio。 |
17
+ | `MCP_CLIENT_LOG` | 默认开启:在声明了 `logging` 能力时,通过 MCP `notifications/message` 把**同类 HTTP 调试摘要**发给已连接的客户端(如 Inspector 日志面板)。设为 `0`、`false`、`off` 可关闭;仅影响发往客户端的通知,不影响 stderr。 |
18
+
@@ -0,0 +1,23 @@
1
+ export declare const BUSINESS_MODULES: readonly [{
2
+ readonly id: 1;
3
+ readonly name: "亚厦模块";
4
+ }, {
5
+ readonly id: 2;
6
+ readonly name: "商转租模块";
7
+ }, {
8
+ readonly id: 7;
9
+ readonly name: "客Saas模块";
10
+ }, {
11
+ readonly id: 10;
12
+ readonly name: "众能商城模块";
13
+ }, {
14
+ readonly id: 11;
15
+ readonly name: "商自有模块";
16
+ }, {
17
+ readonly id: 12;
18
+ readonly name: "配件商城认证模块";
19
+ }];
20
+ export type BusinessModuleId = (typeof BUSINESS_MODULES)[number]["id"];
21
+ export declare const BUSINESS_MODULE_ID_SET: Set<number>;
22
+ export declare function businessModuleIdsDescribe(): string;
23
+ export declare function isBusinessModuleId(id: number): boolean;
@@ -0,0 +1 @@
1
+ export const BUSINESS_MODULES=[{id:1,name:"\u4E9A\u53A6\u6A21\u5757"},{id:2,name:"\u5546\u8F6C\u79DF\u6A21\u5757"},{id:7,name:"\u5BA2Saas\u6A21\u5757"},{id:10,name:"\u4F17\u80FD\u5546\u57CE\u6A21\u5757"},{id:11,name:"\u5546\u81EA\u6709\u6A21\u5757"},{id:12,name:"\u914D\u4EF6\u5546\u57CE\u8BA4\u8BC1\u6A21\u5757"}],BUSINESS_MODULE_ID_SET=new Set(BUSINESS_MODULES.map(e=>e.id));export function businessModuleIdsDescribe(){return BUSINESS_MODULES.map(e=>`${e.id}=${e.name}`).join("\uFF1B")}export function isBusinessModuleId(e){return BUSINESS_MODULE_ID_SET.has(e)}
@@ -0,0 +1,4 @@
1
+ export declare const CREATE_MIX_PATH = "/infrastructure-license/v1/bussinfo/createMix";
2
+ export declare const QUERY_PERSON_PATH = "/api/persons/query";
3
+ export declare const DICTIONARY_INNER_KEY_GET_PATH = "/infrastructure-integration/dictionary/inner/key/get";
4
+ export declare const DICTIONARY_OBJECT_KEY_GET_PATH = "/infrastructure-integration/dictionary/object/key/get";
@@ -0,0 +1 @@
1
+ export const CREATE_MIX_PATH="/infrastructure-license/v1/bussinfo/createMix",QUERY_PERSON_PATH="/api/persons/query",DICTIONARY_INNER_KEY_GET_PATH="/infrastructure-integration/dictionary/inner/key/get",DICTIONARY_OBJECT_KEY_GET_PATH="/infrastructure-integration/dictionary/object/key/get";
@@ -0,0 +1,6 @@
1
+ export type AppConfig = {
2
+ baseUrl: string;
3
+ token: string;
4
+ appId: number;
5
+ };
6
+ export declare function loadConfig(): AppConfig;
package/dist/config.js ADDED
@@ -0,0 +1 @@
1
+ import{z as o}from"zod";const e=10004,i=o.object({BASE_URL:o.string().optional().transform(r=>(r??"").trim()),TOKEN:o.string().optional().transform(r=>(r??"").trim()),X_AUTH_APPID:o.string().optional().transform(r=>{const t=(r??"").trim();if(!t)return e;const n=Number(t);return Number.isFinite(n)?n:e})});export function loadConfig(){const r=i.safeParse(process.env);if(!r.success)throw new Error(`\u914D\u7F6E\u89E3\u6790\u5931\u8D25: ${r.error.message}`);const{BASE_URL:t,TOKEN:n,X_AUTH_APPID:s}=r.data;if(t)try{new URL(t)}catch{throw new Error(`BASE_URL \u4E0D\u662F\u5408\u6CD5 URL: ${t}`)}return{baseUrl:t,token:n,appId:s}}
@@ -0,0 +1,18 @@
1
+ import { type AxiosInstance, type AxiosRequestConfig } from "axios";
2
+ import type { AppConfig } from "./config.js";
3
+ export declare const ERR_NO_BASE_URL = "\u672A\u914D\u7F6E BASE_URL\uFF0C\u8BF7\u5728\u73AF\u5883\u53D8\u91CF\u4E2D\u8BBE\u7F6E\u57FA\u51C6\u5730\u5740\u540E\u518D\u8C03\u7528\u3002";
4
+ export declare function responseDataToText(data: unknown): string;
5
+ export type InternalAxiosRequestConfig = AxiosRequestConfig & {
6
+ skipEnvelopeValidation?: boolean;
7
+ };
8
+ export type ApiEnvelope<T = unknown> = {
9
+ errCode: string;
10
+ message: string;
11
+ data: T;
12
+ };
13
+ export type HttpClient = {
14
+ axios: AxiosInstance;
15
+ get: <T = unknown>(path: string, config?: AxiosRequestConfig) => Promise<T>;
16
+ postJSON: <T = unknown>(path: string, body?: unknown, config?: AxiosRequestConfig) => Promise<T>;
17
+ };
18
+ export declare function createHttpClient(config: AppConfig): HttpClient;
@@ -0,0 +1 @@
1
+ import i from"axios";import{isMcpClientLogEnabled as a,mcpSendLog as u}from"./mcp-logging.js";const p="x-auth-appid",h="x-auth-token";function d(){const e=process.env.MCP_HTTP_DEBUG?.trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}function c(e){const t={};if(!e)return t;for(const[r,s]of Object.entries(e)){const n=r.toLowerCase();n==="x-auth-token"||n==="authorization"?t[r]=s!=null&&String(s)!==""?"[REDACTED]":"":t[r]=s==null?"":String(s)}return t}function m(e){const t=e.headers;if(t&&typeof t=="object"&&"toJSON"in t){const r=t.toJSON();return c(r)}return c(t)}function g(e){if(!d())return;const t=(e.method??"get").toUpperCase(),r=i.getUri(e),s={phase:"request",method:t,url:r,headers:m(e),data:e.data};console.error("[znlh-mcp HTTP] \u8BF7\u6C42",JSON.stringify(s,null,2)),a()&&u("info","znlh-mcp/http",s)}function E(e){if(!d())return;const t=e.headers&&typeof e.headers=="object"&&"toJSON"in e.headers?e.headers.toJSON():e.headers,r={phase:"response",status:e.status,statusText:e.statusText,headers:c(t),data:e.data};console.error("[znlh-mcp HTTP] \u54CD\u5E94",JSON.stringify(r,null,2)),a()&&u("info","znlh-mcp/http",r)}function S(e){if(!d())return;if(!i.isAxiosError(e)){console.error("[znlh-mcp HTTP] \u9519\u8BEF",String(e)),a()&&u("error","znlh-mcp/http",{phase:"error",message:String(e)});return}const t=e.response,r={phase:"error",message:e.message,code:e.code,requestUrl:e.config?i.getUri(e.config):void 0,requestMethod:e.config?.method,status:t?.status,statusText:t?.statusText,responseHeaders:t?.headers?c(typeof t.headers.toJSON=="function"?t.headers.toJSON():t.headers):void 0,responseData:t?.data};console.error("[znlh-mcp HTTP] \u9519\u8BEF",JSON.stringify(r,null,2)),a()&&u("error","znlh-mcp/http",r)}export const ERR_NO_BASE_URL="\u672A\u914D\u7F6E BASE_URL\uFF0C\u8BF7\u5728\u73AF\u5883\u53D8\u91CF\u4E2D\u8BBE\u7F6E\u57FA\u51C6\u5730\u5740\u540E\u518D\u8C03\u7528\u3002";export function responseDataToText(e){return e===void 0?"":typeof e=="string"?e:JSON.stringify(e)}function y(e){if(e===null||typeof e!="object")return!1;const t=e;return"errCode"in t&&"message"in t&&"data"in t&&typeof t.errCode=="string"&&typeof t.message=="string"}function T(e){return e===""||e==="0"}function j(e){return e.skipEnvelopeValidation!==!1}function H(e){e.interceptors.response.use(t=>{const r=t.config;if(j(r))return t;const{status:s,data:n}=t;if(s<200||s>=300)return Promise.reject(new Error(`HTTP ${s} ${t.statusText||""}`.trim()));if(!y(n))return Promise.reject(new Error("\u54CD\u5E94\u4F53\u4E0D\u662F { errCode, message, data } \u7ED3\u6784"));if(!T(n.errCode)){const o=n.message?.trim()||`\u4E1A\u52A1\u5931\u8D25 errCode=${JSON.stringify(n.errCode)}`;return Promise.reject(new Error(o))}return t},t=>{if(i.isAxiosError(t)){const r=t.response?.data;let s=t.message;if(r!=null)if(typeof r=="object"&&r!==null&&"message"in r){const n=r.message;typeof n=="string"&&n.trim()?s=n:s=responseDataToText(r)}else typeof r=="string"?s=r:s=responseDataToText(r);return Promise.reject(new Error(s))}return Promise.reject(t instanceof Error?t:new Error(String(t)))})}export function createHttpClient(e){const t={[p]:String(e.appId)};e.token&&(t[h]=e.token);const r=i.create({baseURL:e.baseUrl||void 0,headers:t,validateStatus:()=>!0}),s=!!e.baseUrl?.trim();return r.interceptors.request.use(n=>s?n:Promise.reject(new Error(ERR_NO_BASE_URL))),r.interceptors.request.use(n=>(g(n),n)),r.interceptors.response.use(n=>(E(n),n),n=>(S(n),Promise.reject(n))),H(r),{axios:r,async get(n,o){return(await r.get(n,{...o,headers:{Accept:"application/json",...l(o?.headers)},skipEnvelopeValidation:!1})).data.data},async postJSON(n,o,f){return(await r.post(n,o,{...f,headers:{"Content-Type":"application/json",...l(f?.headers)},skipEnvelopeValidation:!1})).data.data}}}function l(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[r,s]of Object.entries(e))s!=null&&(t[r]=String(s));return t}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{McpServer as r}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as n}from"@modelcontextprotocol/sdk/server/stdio.js";import{loadConfig as e}from"./config.js";import{bindMcpLogging as i,mcpSendLog as t}from"./mcp-logging.js";import{registerTools as m}from"./tool/register.js";const p=e(),o=new r({name:"znlh-mcp",version:"0.1.0"},{capabilities:{logging:{}}});i(o),m(o,p);const c=new n;await o.connect(c),t("info","znlh-mcp",{event:"started",name:"znlh-mcp",version:"0.1.0"});
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function isMcpClientLogEnabled(): boolean;
3
+ export declare function bindMcpLogging(server: McpServer): void;
4
+ type McpLogLevel = "debug" | "info" | "notice" | "warning" | "error" | "critical" | "alert" | "emergency";
5
+ export declare function mcpSendLog(level: McpLogLevel, logger: string, data: unknown): void;
6
+ export {};
@@ -0,0 +1 @@
1
+ let n=null;export function isMcpClientLogEnabled(){const e=process.env.MCP_CLIENT_LOG?.trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}export function bindMcpLogging(e){n=e}export function mcpSendLog(e,o,r){!isMcpClientLogEnabled()||!n||n.server.sendLoggingMessage({level:e,logger:o,data:r}).catch(()=>{})}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type HttpClient } from "../http-client.js";
3
+ export declare function registerBackendRequestTool(server: McpServer, http: HttpClient): void;
@@ -0,0 +1,3 @@
1
+ import{z as a}from"zod";import{responseDataToText as E}from"../http-client.js";export function registerBackendRequestTool(o,i){o.tool("backend_request","\u5728 BASE_URL \u4E0B\u53D1\u8D77 HTTP \u8BF7\u6C42\uFF1B\u81EA\u52A8\u5E26 x-auth-appid\u3001x-auth-token\u3002\u9700\u914D\u7F6E BASE_URL\u3002",{path:a.string().describe("\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u5982 /api/v1/health"),method:a.enum(["GET","POST","PUT","PATCH","DELETE"]).optional().describe("HTTP \u65B9\u6CD5\uFF0C\u9ED8\u8BA4 GET"),body:a.string().optional().describe("\u8BF7\u6C42\u4F53\uFF0CJSON \u5B57\u7B26\u4E32")},async({path:c,method:s="GET",body:r})=>{const n=c.trim(),p=n.startsWith("/")?n:`/${n}`;let e;if(r?.trim())try{e=JSON.parse(r)}catch{e=r}const T=e!==void 0&&s!=="GET"&&s!=="DELETE";try{const t=await i.axios.request({method:s,url:p,...T?{data:e,headers:{"Content-Type":"application/json"}}:{},skipEnvelopeValidation:!0});return{content:[{type:"text",text:`${t.status} ${t.statusText||""}
2
+
3
+ ${E(t.data)}`}],isError:t.status<200||t.status>=300}}catch(t){return{content:[{type:"text",text:t instanceof Error?t.message:String(t)}],isError:!0}}})}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type HttpClient } from "../http-client.js";
3
+ export declare function registerDictionaryTool(server: McpServer, http: HttpClient): void;
@@ -0,0 +1 @@
1
+ import{z as i}from"zod";import{responseDataToText as s}from"../http-client.js";import{DICTIONARY_INNER_KEY_GET_PATH as c,DICTIONARY_OBJECT_KEY_GET_PATH as u}from"../common/urls.js";const y=i.object({key:i.string().describe("\u5B57\u5178\u952E key\uFF0C\u5FC5\u586B"),parent_key:i.string().optional().describe("\u7236\u7EA7\u5B57\u5178\u952E parentKey\uFF0C\u53EF\u9009")});function m(o,a){const e=o.trim();if(!e)return{error:"key \u4E0D\u80FD\u4E3A\u7A7A\u3002"};const n={key:e},r=a?.trim();return r&&(n.parentKey=r),{params:n}}export function registerDictionaryTool(o,a){o.tool("dictionary_inner_key_get",`\u67E5\u8BE2\u5355\u4E2A\u6570\u636E\u5B57\u5178\u3002GET ${c}\uFF1B`,y.shape,async({key:e,parent_key:n})=>{const r=m(e,n);if("error"in r)return{content:[{type:"text",text:r.error}],isError:!0};try{const t=await a.get(c,{params:r.params});return{content:[{type:"text",text:s(t)}],isError:!1}}catch(t){return{content:[{type:"text",text:t instanceof Error?t.message:String(t)}],isError:!0}}}),o.tool("dictionary_object_key_get","\u67E5\u8BE2\u6570\u636E\u5B57\u5178\u5BF9\u8C61\uFF08\u542B\u5B50\u8282\u70B9\u7B49\u7ED3\u6784\uFF09\u3002",y.shape,async({key:e,parent_key:n})=>{const r=m(e,n);if("error"in r)return{content:[{type:"text",text:r.error}],isError:!0};try{const t=await a.get(u,{params:r.params});return{content:[{type:"text",text:s(t)}],isError:!1}}catch(t){return{content:[{type:"text",text:t instanceof Error?t.message:String(t)}],isError:!0}}})}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGreetTool(server: McpServer): void;
@@ -0,0 +1 @@
1
+ import{z as o}from"zod";export function registerGreetTool(t){t.tool("greet","\u5411\u6307\u5B9A\u540D\u79F0\u95EE\u597D",{name:o.string().describe("\u8981\u95EE\u5019\u7684\u5BF9\u8C61\u540D\u79F0")},async({name:e})=>({content:[{type:"text",text:`\u4F60\u597D\uFF0C${e}\uFF01`}]}))}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type HttpClient } from "../http-client.js";
3
+ export declare function registerOpenapiTools(server: McpServer, http: HttpClient): void;
@@ -0,0 +1 @@
1
+ import{z as e}from"zod";import{responseDataToText as p}from"../http-client.js";import{businessModuleIdsDescribe as i,isBusinessModuleId as u}from"../common/module-ids.js";import{CREATE_MIX_PATH as o}from"../common/urls.js";const _=e.number().int().refine(u,{message:`module_ids \u6BCF\u9879\u987B\u4E3A\u5DF2\u5B9A\u4E49\u6A21\u5757\uFF1A${i()}`}),b=e.object({isv_method:e.string().describe("ISV \u65B9\u6CD5\u6807\u8BC6\uFF0C\u5982 order.create.v1"),api_name:e.string().describe("API \u5C55\u793A\u540D\u79F0"),api_service_url:e.string().describe("\u63A5\u53E3\u8DEF\u5F84"),http_method:e.enum(["GET","POST"]).describe("HTTP \u65B9\u6CD5"),module_ids:e.array(_).min(1).describe(`\u6A21\u5757ID\uFF08\u53EF\u591A\u9009\uFF09\uFF1A${i()}`)});export function registerOpenapiTools(n,m){n.tool("openapi_bussinfo_create_mix",`\u521B\u5EFAOpenAPI\uFF1APOST ${o}\u3002`,{service_id:e.string().describe("\u670D\u52A1\u63D0\u4F9B\u65B9"),isv_method:b.describe("\u5355\u6761 ISV \u65B9\u6CD5\uFF08\u6BCF\u6B21\u8C03\u7528\u4EC5\u4E00\u6761\uFF09")},async({service_id:d,isv_method:c})=>{const t=d.trim();if(!t)return{content:[{type:"text",text:"service_id \u4E0D\u80FD\u4E3A\u7A7A\u3002"}],isError:!0};const s=c,a={serviceId:t,bussName:t,bussDesc:t,bussOwner:t,isvMethods:[{apiName:s.api_name.trim(),apiServiceUrl:s.api_service_url.trim(),httpMethod:s.http_method,isvMethod:s.isv_method.trim(),moduleIds:s.module_ids}]};try{const r=await m.postJSON(o,a);return{content:[{type:"text",text:p(r)}],isError:!1}}catch(r){return{content:[{type:"text",text:r instanceof Error?r.message:String(r)}],isError:!0}}})}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type HttpClient } from "../http-client.js";
3
+ export declare function registerQueryPersonTool(server: McpServer, http: HttpClient): void;
@@ -0,0 +1 @@
1
+ import{z as n}from"zod";import{responseDataToText as c}from"../http-client.js";import{QUERY_PERSON_PATH as s}from"../common/urls.js";export function registerQueryPersonTool(i,d){i.tool("query_person",`\u67E5\u8BE2\u4EBA\u5458\u4FE1\u606F\uFF1APOST JSON \u5230\u67E5\u8BE2\u63A5\u53E3\uFF0C\u8BF7\u6C42\u4F53\u4E3A { personId } \u6216 { keyword }\uFF1B\u6210\u529F\u8FD4\u56DE\u4E1A\u52A1 data\u3002\u8DEF\u5F84\uFF1A${s}\uFF08\u89C1 src/common/urls.ts\uFF09\u3002`,{personId:n.string().optional().describe("\u4EBA\u5458\u552F\u4E00 ID\uFF1B\u4E0E keyword \u81F3\u5C11\u586B\u4E00\u4E2A"),keyword:n.string().optional().describe("\u5173\u952E\u8BCD\uFF08\u5982\u59D3\u540D\uFF09\uFF1B\u4E0E personId \u81F3\u5C11\u586B\u4E00\u4E2A")},async o=>{const t=o.personId?.trim(),e=o.keyword?.trim();if(!t&&!e)return{content:[{type:"text",text:"\u8BF7\u63D0\u4F9B personId \u6216 keyword \u4E4B\u4E00\u3002"}],isError:!0};const p=t?{personId:t}:{keyword:e};try{const r=await d.postJSON(s,p);return{content:[{type:"text",text:c(r)}],isError:!1}}catch(r){return{content:[{type:"text",text:r instanceof Error?r.message:String(r)}],isError:!0}}})}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AppConfig } from "../config.js";
3
+ export declare function registerTools(server: McpServer, config: AppConfig): void;
@@ -0,0 +1 @@
1
+ import{createHttpClient as i}from"../http-client.js";import{registerBackendRequestTool as e}from"./backend-request.js";import{registerOpenapiTools as m}from"./openapi.js";import{registerGreetTool as p}from"./greet.js";import{registerQueryPersonTool as n}from"./query-person.js";import{registerDictionaryTool as f}from"./dictionary.js";export function registerTools(o,r){const t=i(r);p(o),n(o,t),f(o,t),m(o,t),e(o,t)}
package/dist/url.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function joinBaseUrl(base: string, path: string): string;
package/dist/url.js ADDED
@@ -0,0 +1 @@
1
+ export function joinBaseUrl(n,t){const i=n.endsWith("/")?n.slice(0,-1):n,o=t.startsWith("/")?t:`/${t}`;return`${i}${o}`}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@seaxlab/znlh-mcp",
3
+ "version": "0.0.4",
4
+ "type": "module",
5
+ "description": "ZNLH MCP server (Node.js, stdio)",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "znlh-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/**/*.js",
12
+ "dist/**/*.d.ts",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "node scripts/clean-dist.mjs && tsc",
17
+ "build:release": "node scripts/clean-dist.mjs && tsc && node scripts/minify-dist.mjs",
18
+ "prepublishOnly": "npm run build:release",
19
+ "start": "node dist/index.js",
20
+ "dev": "tsx watch src/index.ts",
21
+ "dev:once": "tsx src/index.ts",
22
+ "inspector": "bash scripts/mcp-inspector.sh"
23
+ },
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.25.0",
29
+ "axios": "^1.7.0",
30
+ "zod": "^3.24.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^22.0.0",
34
+ "esbuild": "^0.25.12",
35
+ "tsx": "^4.19.0",
36
+ "typescript": "^5.7.0"
37
+ }
38
+ }