关于 MCP Server - A Node In Layers Package for building MCP Servers
这是用于构建 MCP 服务的 Node In Layers 软件包,可将应用域、功能和模型 CRUD 操作提供给 AI。开发者可配置能力导航、隐藏组件,或使用扁平模式直接暴露功能工具。
主要功能
- 01暴露功能和模型 CRUD 工具
- 02按领域组织工具
- 03可配置 START_HERE 指引
- 04扁平模式直接提供功能工具
- 05隐藏指定组件
- 06注册自定义工具
适用场景
- 01向 AI 客户端提供应用功能
- 02通过 MCP 提供模型 CRUD 操作
- 03借助 START_HERE 减少导航调用
- 04限制调用方可访问的组件
MCP 相关
它用于构建 MCP 服务,向 MCP 客户端暴露领域、功能和模型 CRUD 操作。客户端可先发现并查看能力说明,再执行操作;也可注册自定义工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
MCP Server - 用于构建 MCP 服务的 Node In Layers 包
一个用于构建 MCP 服务的 Node In Layers 包。它会将你的领域、功能和模型 CRUD 操作公开为 MCP 工具,供 AI 发现并调用。配套库:@node-in-layers/mcp-client(用于功能、模型和工具的共享协议)。
该系统具有 self-describing 特性,会自动将工具组织成经过优化且高效的系统,从而减少工具总数。它还会自动添加提示词和示例,大幅提升 AI 在系统中选择工具和准确格式化内容的能力,适用于拥有数百乃至数千个工具的系统。
使用方法
1. 安装
npm install @node-in-layers/mcp-server
2. 配置
// /config.base.mts
import { CoreNamespace } from '@node-in-layers/core'
import { McpNamespace, HttpConnection } from '@node-in-layers/mcp-server'
export default () => ({
systemName: 'your-system-name',
[CoreNamespace.root]: {
/* 1. Add to the Apps List */
apps: await Promise.all([
// Other Very Early Modules
//import('@node-in-layers/data/index.js'),
// Insert Here
import('@node-in-layers/mcp-server/index.js'),
// Insert Your Domains Here
]),
/* 2. Add mcp layer. NOTE: You must have entries between features and mcp */
layerOrder: ['services', 'features', ['entries', 'mcp']], // can also be ['entries', 'express', 'mcp']
},
/* 3. Add Mcp Server Configurations */
[McpNamespace]: {
// Required: The configuration of the server itself.
server: {
connection: {
type: 'http',
url: 'http://localhost',
port: 4000,
} as HttpConnection,
},
// Optional arguments go here.
},
})
3. 现在可用的内容
- 功能会自动公开(除非明确隐藏)
- 模型 CRUD 操作会自动公开(除非明确隐藏)
- 功能现在可以使用
mcp层,其中包含命名空间McpNamespace中的其他能力。(稍后说明)
4. 运行服务
你可以通过以下方式在简单脚本中轻松运行服务:
import { McpNamespace } from '@node-in-layers/mcp-server'
const system: System = (await core.loadSystem<SystemConfig>({
environment,
})) as any // "System" is your typed System object.
await system.mcp[McpNamespace].start(context)
使用 ./bin/mcp_server.mts 文件的示例(可随意复制粘贴)
#!/usr/bin/env tsx
import esMain from 'es-main'
import { ArgumentParser } from 'argparse'
import * as core from '@node-in-layers/core'
import { McpNamespace } from '@node-in-layers/mcp-server'
import { SystemConfig } from '../src/types.js'
import { System } from '../src/system/types.js'
const _parseArguments = () => {
const parser = new ArgumentParser({
description: 'Starts the MCP server.',
})
parser.add_argument('environment', {
help: 'The environment for the service.',
})
return parser.parse_args()
}
const startServer = async (environment: string) => {
const system = (await core.loadSystem<SystemConfig>({
environment,
})) as unknown as System
if (system.config[McpNamespace].server.connection.type === 'http') {
console.info(
`Starting MCP server on ${system.config[McpNamespace].server.connection.port}...`
)
}
process.on('SIGINT', async function () {
await system.services['@node-in-layers/data'].cleanup()
process.exit()
})
await system.mcp[McpNamespace].start(system)
}
if (esMain(import.meta)) {
const args = _parseArguments()
startServer(args.environment).catch((error: any) => {
console.error('Failed to start the server:', error)
process.exit(1)
})
}
背景与工作原理
MCP 接口(领域、功能、模型)
MCP 工具界面按领域组织,然后是功能和模型:
- 领域 — AI 可以列出领域(
list_domains),然后针对每个领域列出功能(list_features),并在有模型时列出模型。只有公开了功能或模型的领域才会显示。 - 功能 — 对于指定的领域/功能,AI 可以获取其架构(
describe_feature)并运行它(execute_feature)。 - 模型 — 对于指定的领域/模型,AI 可以获取其架构,并运行保存、检索、删除、搜索、bulkInsert、bulkDelete 操作。
返回给 AI 的文档(包括 START_HERE 返回的内容)可配置。默认情况下,服务会提供说明,引导 AI:
- 列出领域。
- 列出某个领域中的功能(和模型)。
- 需要架构时,描述功能或模型。
- 使用正确的参数执行功能和模型 CRUD 操作。
因此,AI 会通过可配置的“从这里开始”内容和默认系统条目了解系统结构,然后根据需要使用工具进行列出、描述和执行操作。
扁平模式(仅功能工具)
如果你希望工具界面非常精简、重点突出(例如,只有一个函数的系统),可以让 MCP 服务以扁平模式运行。
在扁平模式下,服务会:
- 将每个功能函数公开为独立的 MCP 工具,名称为
domain_featureName。 - 不公开 Node-in-Layers 导航工具(
START_HERE、list_domains、list_features、describe_feature、execute_feature)。 - 不公开任何模型 CRUD 工具(
list_models、describe_model、save、retrieve、delete、search、bulkInsert、bulkDelete)。 - 仍会公开你通过
addTool()/addAnnotatedFunction()明确注册的任何工具。
通过以下方式启用:
// /config.base.mts
import { McpNamespace } from '@node-in-layers/mcp-server'
export default () => ({
// ...
[McpNamespace]: {
mode: 'flat',
server: { connection: { type: 'cli' } },
},
})
隐藏组件
你可以限制调用方可见(以及可执行)的内容(例如特定领域、功能或所有模型 CRUD 操作),只公开预期的工具界面。
在 MCP 配置中配置 hideComponents:
- paths — 要隐藏的点分隔路径,例如
myDomain、myDomain.myFeature、myDomain.cruds、myDomain.cruds.MyModel。 - domains — 要完全隐藏的领域名称(它们不会出现在
list_domains中)。 - allModels — 如果为
true,则不公开任何模型 CRUD 工具。
未隐藏的内容均保持可用。完整结构请参阅配置详情。
示例(部分配置):
// /config.base.mts
import { McpNamespace } from '@node-in-layers/mcp-server'
export default () => ({
// ...
[McpNamespace]: {
// ...
hideComponents: {
// Completely hide these domains from the MCP surface
domains: ['internalAdmin', 'experimental'],
// Hide specific paths (domains, features, or models)
paths: [
'billing.cruds', // hide all models in the billing domain
'users.cruds.ApiKeys', // hide a single model. (The ApiKeys table located in the users domain)
'debug.internalFeature', // hide a specific feature
],
// Or hide all models everywhere. Good for "feature" oriented systems.
allModels: false, // set true to hide all model CRUD tools
},
},
})
系统描述
在 systemDescription 下设置系统的静态元数据,这些元数据会包含在起始说明响应中:
- description — 面向 AI 的简短系统描述。
- version — 系统版本字符串。
这里适合填写“这个系统是什么”以及版本信息;它不会控制系统中有哪些工具,也不会控制 START_HERE 工具包含哪些内容(这些由 startHere 配置)。
示例(部分配置):
// /config.base.mts
import { McpNamespace } from '@node-in-layers/mcp-server'
export default () => ({
// ...
[McpNamespace]: {
// ...
systemDescription: {
description: 'Order management and billing system for ACME Corp.',
version: '2.3.0',
},
},
})
从这里开始
START_HERE 工具让系统变得易于导航:系统会指示 AI 首先调用该工具(或在用户寻求帮助时调用)。其响应由以下内容构成:
- 系统元数据 — 配置中的
systemName、systemDescription、systemVersion。 - 默认系统条目 — 内置文档(例如“这是一个按领域分层的系统”“MCP 导航工作流”“跨层属性”)。你可以通过
startHere.hideDefaultSystemEntries关闭这些条目。 - 可选:包含领域 / 包含功能 — 如果
startHere.includeDomains为 true,响应会包含当前领域列表(相当于已调用list_domains)。如果startHere.includeFeatures为 true,还会包含每个领域的功能列表(相当于已为每个领域调用list_features)。这样一来,AI 无需额外调用工具即可获取领域和 / 或功能。 - 使用示例 — 你在
startHere.examplesOfUse下添加的自定义条目。这里用于记录较高层级的流程(例如“运行功能 A,然后运行 B,最后运行 C”)。内置文档会介绍领域、功能和模型,但不会介绍你的应用专属流程。请将这些流程放在examplesOfUse中,并使用仅含少量说明文字的 JSON 对象示例,以便 AI 直接应用。
包含领域 / 包含功能
启用这些选项相当于预先运行 list_domains 和 / 或 list_features,并将结果嵌入 START_HERE。缺点是会增加上下文大小:对于大型系统(工具很多),这会占用大量上下文并引入干扰信息。对于小型系统(约有 1–10 个工具),通常没有问题。对于较大型的系统,建议使用使用示例,并让 AI 在需要时调用 list_domains / list_features。
示例(部分配置):
// /config.base.mts
import { McpNamespace } from '@node-in-layers/mcp-server'
export default () => ({
// ...
[McpNamespace]: {
// ...
startHere: {
// Optional: override tool identity
name: 'START_HERE',
description:
'BEFORE YOU DO ANYTHING, call this first to learn how to navigate the system.',
// What to include in the start-here response
hideDefaultSystemEntries: false, // do we want the ones that come by default? Usually this is yes.
includeDomains: true, // Should we go ahead and tell it the domains? Commonly this should be true.
includeFeatures: false, // Should we tell them all the features on the first go? In most cases this should be FALSE. Unless its a small system with few functions.
// Higher-level flows through your system
examplesOfUse: [
{
name: 'Create order then fetch it',
description: 'Typical flow that creates an order and then retrieves it.',
// Giving ACTUAL examples (json data, + small annotations) works amazingly.
example: `
```markdown
// 1. Create an order
{ "tool": "execute_feature", "args": { "domain": "orders", "featureName": "createOrder" } }
// 2. Get the order by id (using the id from step 1)
{ "tool": "execute_feature", "args": { "domain": "orders", "featureName": "getOrderById" } }
`,
tags: ['orders', 'flow'],
},
],
},
}, })
---
## Extending with custom tools
You can add your own MCP tools via the MCP layer using `addTool`. Use this from a layer that has access to `mcp[McpNamespace]` (e.g. after the MCP layer in the stack).
Example (conceptual):
```typescript
// In a layer that runs after the MCP layer and has context.mcp[McpNamespace]
const mcp = context.mcp[McpNamespace]
mcp.addTool({
name: 'my_custom_tool',
description: 'Does something custom',
inputSchema: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] },
outputSchema: { type: 'object' },
execute: async (input) => ({ result: input.id }),
})
随后,你的工具会与内置的领域 / 功能 / 模型工具一同对外提供。
如何运行服务
- start — 启动 MCP 服务(监听配置中定义的连接)。
mcp[McpNamespace].start(systemContext, options?) - getApp — 获取 Express 应用(用于 HTTP/SSE),以便将其挂载到你自己的服务中。
mcp[McpNamespace].getApp(options?)
当 MCP 服务是主进程时,使用 start。当你要与现有 Express 应用组合使用时,使用 getApp(例如将 MCP 应用挂载到某个路径)。
中间件和路由
- addPreRouteMiddleware(middleware) — 添加在 MCP 路由处理之前运行的 Express 中间件。
- addCrossLayerPropMiddleware(middleware) — 添加中间件,用于提取请求级数据(例如经过身份验证的
user),并将其传递到跨层属性中,供下游函数使用。 - addAdditionalRoute(route) — 在同一个应用中注册额外的 Express 路由(例如健康检查或管理路由)。
请在设置期间调用这些方法(例如,在能够访问 mcp[McpNamespace] 的层中),并在启动服务或使用应用之前完成调用。
更改日志记录配置
日志记录在 MCP 配置的 logging 部分中进行配置。你可以控制日志级别,还可以选择为每条请求 / 响应日志添加结构化数据。
- requestLogLevel / responseLogLevel:覆盖传入请求和传出响应的默认日志级别(
info)。 - requestLogGetData(input):将原始请求输入映射为要记录的额外数据的函数。
- responseLogGetData(result):将原始工具结果映射为要记录的额外数据的函数。
示例(部分配置):
// /config.base.mts
import { McpNamespace } from '@node-in-layers/mcp-server'
export default () => ({
// ...
[McpNamespace]: {
// ...
logging: {
// Adjust verbosity
requestLogLevel: 'debug',
responseLogLevel: 'info',
// Attach additional request information to the log.
requestLogGetData: (input: Request) => ({
something: input.something,
}),
responseLogGetData: (input: Request) => ({
// Shape this to your needs; example:
truncated: true,
}),
},
},
})
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。