进阶玩法
开发自定义工具
写一个 MCP server 暴露你的工具 — 10 行代码起步。
两种打包方式
Kition 的自定义工具有两条路径:内嵌工具包(TypeScript bundle 丢进 .kition/tools/,启动时由内置运行时加载)或者独立的 MCP server(任意语言,通过 stdio / SSE 暴露)。内嵌方式适合轻量、纯函数式的工具;MCP 方式适合需要状态、长连接、或者要在多个 Vault 间复用的场景。
两种方式在 Agent 看来都是同一类调用 — 工具 schema 一致,权限模型一致,Hooks 同样可以拦截。区别只在分发:内嵌工具跟 Vault 走,MCP server 跟机器走。
从用户体验上说,内嵌工具是“写一次就能用”的最短路径;MCP server 则是当工具需要被多个 Vault、多台机器、甚至多个团队共享时的正解。
内嵌工具骨架
把下面这个文件存为 .kition/tools/word-count.ts,Kition 启动时会自动扫描、类型检查并注册。默认导出必须是 defineTool({...}),Kition 用 schema 做参数校验、用 run 做执行。
ctx 参数提供了日志、Vault 文件系统、当前 session 元信息、以及 secrets 的访问接口 — 不用自己 require 任何 Kition 内部模块。
import { defineTool } from '@kition/tools'
import { z } from 'zod'
export default defineTool({
name: 'word_count',
title: 'Word count',
description: 'Count words in a string, optionally splitting on punctuation.',
input: z.object({
text: z.string().min(1),
splitOnPunctuation: z.boolean().default(false),
}),
output: z.object({
words: z.number(),
chars: z.number(),
}),
async run({ input, ctx }) {
const re = input.splitOnPunctuation ? /[\s\p{P}]+/u : /\s+/u
const words = input.text.trim().split(re).filter(Boolean).length
ctx.log.info('counted', { words })
return { words, chars: input.text.length }
},
})访问 Vault 与 secrets
复杂一点的工具往往要读 Vault 的笔记、调外部 API、或者持久化点东西。ctx 上挂着对应的 API — 文件读写走 ctx.vault,secrets 走 ctx.secrets(来自 Keychain / DPAPI / libsecret),HTTP 走 ctx.fetch(自动应用 provider 路由与重试策略)。
import { defineTool } from '@kition/tools'
import { z } from 'zod'
export default defineTool({
name: 'jira_create_issue',
title: 'Create Jira issue',
description: 'Create a Jira issue from the current note.',
input: z.object({
project: z.string(),
summary: z.string(),
notePath: z.string(),
}),
async run({ input, ctx }) {
const body = await ctx.vault.readFile(input.notePath)
const token = await ctx.secrets.get('jira.api_token')
const res = await ctx.fetch('https://acme.atlassian.net/rest/api/3/issue', {
method: 'POST',
headers: {
authorization: `Basic ${token}`,
'content-type': 'application/json',
},
body: JSON.stringify({
fields: {
project: { key: input.project },
summary: input.summary,
description: body,
issuetype: { name: 'Task' },
},
}),
})
if (!res.ok) throw new Error(`jira ${res.status}`)
const json = await res.json() as { key: string }
return { key: json.key, url: `https://acme.atlassian.net/browse/${json.key}` }
},
})独立 MCP server
如果工具需要外部 API、数据库连接、或者你想用 Python / Go / Rust 写,就走 MCP。任何符合 Model Context Protocol 的 server 都可以挂载。下面这个最小 TypeScript 例子展示了 tools/list 和 tools/call 两个核心 handler。
生产环境我们建议用 stdio 传输 — 启动快、隔离好、不占端口。SSE 传输适合 server 跑在远端的场景(比如内部工具服务)。
import { Server } from '@modelcontextprotocol/sdk/server'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio'
const server = new Server({ name: 'word-count', version: '0.1.0' })
server.setRequestHandler('tools/list', () => ({
tools: [{
name: 'word_count',
description: 'Count words in a string',
inputSchema: {
type: 'object',
properties: { text: { type: 'string' } },
required: ['text'],
},
}],
}))
server.setRequestHandler('tools/call', async (req) => {
const text = req.params.arguments.text as string
const words = text.trim().split(/\s+/).filter(Boolean).length
return { content: [{ type: 'text', text: String(words) }] }
})
await server.connect(new StdioServerTransport())注册到 Kition
内嵌工具不用配置 — 文件存在就生效。MCP server 要在 .kition/mcp.json 里加一条 stdio 配置,重启 Agent 之后工具会出现在 /tools 列表里。
想要团队成员都用同一套工具?把 .kition/mcp.json 提交到 Vault 的 git 仓库 — 拉下来即可,所有 MCP 配置都是声明式的。
{
"servers": {
"word-count": {
"type": "stdio",
"command": "node",
"args": ["./scripts/word-count-server.js"],
"env": { "LOG_LEVEL": "info" }
},
"internal-tools": {
"type": "sse",
"url": "https://tools.internal.acme.com/mcp",
"headers": { "authorization": "Bearer ${env:INTERNAL_TOOLS_TOKEN}" }
}
}
}权限与 Hooks
- 工具默认是“ask” — 首次调用要用户确认,可在设置里改成 allow / deny
- 通过
permissions.tools[name]做精细控制,比如network.fetch限定域名 - Hooks 可以在
pre_tool_use/post_tool_use拦截,做合规、审计、脱敏 - 失败时返回非零退出码或 throw — Agent 会看到完整 stack
- 所有工具调用自动记录到
.kition/audit.jsonl,含输入 / 输出 / 时长
调试技巧
kition tools list打印当前 Vault 已加载的工具与来源kition tools call word_count --json '{"text":"hi there"}'不走 Agent 直接调用- MCP server 的 stderr 会进
~/Library/Logs/Kition/mcp-*.log - 类型不对 / schema 不合法时启动日志里会有清晰的 zod / ajv 错误
- 在工具里
ctx.log.debug(...)—KITION_LOG_LEVEL=debug后即可看到