@jmtrin/kevin-mcp 1.4.0 → 1.5.0

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/dist/server.js CHANGED
@@ -12,7 +12,7 @@ import { resolveEnv } from "@jmtrin/kevin-core";
12
12
  import { resolveMcpIdentity, readSettingOverride } from "./identity.js";
13
13
  import { createReadTools } from "./tools/read.js";
14
14
  import { createWriteTools } from "./tools/write.js";
15
- const KEVIN_VERSION = "1.4.0";
15
+ const KEVIN_VERSION = "1.5.0";
16
16
  const { values } = parseArgs({
17
17
  options: {
18
18
  help: { type: "boolean", default: false },
@@ -132,18 +132,7 @@ const registry = [
132
132
  ];
133
133
  // Register with MCP server
134
134
  for (const tool of registry) {
135
- // SDK expects zod-like? We pass empty schema via inputSchema passthrough; use registerTool with zod raw shape
136
- // For compatibility, we register with empty zod object via SDK's internal conversion
137
- // Use any to bypass typing
138
- server.registerTool(tool.name, { description: tool.description, inputSchema: tool.inputSchema }, async (args) => {
139
- // Wrap already does metrics; but ping needs manual wrap? Use tool.handler directly with wrapper already applied for read/write tools.
140
- // For ping, apply wrap
141
- if (tool.name === "ping") {
142
- const w = wrap("mcp.read", tool.handler);
143
- return await w(args);
144
- }
145
- return await tool.handler(args).then((r) => ({ content: [{ type: "text", text: JSON.stringify(r) }] }));
146
- });
135
+ server.registerTool(tool.name, { description: tool.description, inputSchema: tool.inputSchema }, wrap("mcp.read", tool.handler));
147
136
  }
148
137
  const transport = new StdioServerTransport();
149
138
  await server.connect(transport);
@@ -20,14 +20,6 @@ export function createReadTools(opts) {
20
20
  const mismatch = assertScope(identity.repoId, args.repo_id);
21
21
  if (mismatch)
22
22
  return mismatch;
23
- try {
24
- metrics.incr("mcp_requests_total", 1);
25
- }
26
- catch { }
27
- try {
28
- metrics.incr("mcp_reads_served", 1);
29
- }
30
- catch { }
31
23
  const svc = memService();
32
24
  const memories = svc.query({
33
25
  text: args.query,
@@ -50,14 +42,6 @@ export function createReadTools(opts) {
50
42
  const mismatch = assertScope(identity.repoId, args.repo_id);
51
43
  if (mismatch)
52
44
  return mismatch;
53
- try {
54
- metrics.incr("mcp_requests_total", 1);
55
- }
56
- catch { }
57
- try {
58
- metrics.incr("mcp_reads_served", 1);
59
- }
60
- catch { }
61
45
  const svc = memService();
62
46
  const mem = svc.getById(args.id);
63
47
  if (!mem)
@@ -73,14 +57,6 @@ export function createReadTools(opts) {
73
57
  const mismatch = assertScope(identity.repoId, args.repo_id);
74
58
  if (mismatch)
75
59
  return mismatch;
76
- try {
77
- metrics.incr("mcp_requests_total", 1);
78
- }
79
- catch { }
80
- try {
81
- metrics.incr("mcp_reads_served", 1);
82
- }
83
- catch { }
84
60
  const svc = memService();
85
61
  const memories = svc.getRelevant({
86
62
  query: args.query,
@@ -108,14 +84,6 @@ export function createReadTools(opts) {
108
84
  const mismatch = assertScope(identity.repoId, args.repo_id);
109
85
  if (mismatch)
110
86
  return mismatch;
111
- try {
112
- metrics.incr("mcp_requests_total", 1);
113
- }
114
- catch { }
115
- try {
116
- metrics.incr("mcp_reads_served", 1);
117
- }
118
- catch { }
119
87
  const res = kevinWhy(store, args.query);
120
88
  if (!res)
121
89
  return { error: "not_found", query: args.query, provenance: buildProvenance(identity) };
@@ -128,14 +96,6 @@ export function createReadTools(opts) {
128
96
  inputSchema: {},
129
97
  handler: async (args) => {
130
98
  // status bypasses mismatch but reports both
131
- try {
132
- metrics.incr("mcp_requests_total", 1);
133
- }
134
- catch { }
135
- try {
136
- metrics.incr("mcp_reads_served", 1);
137
- }
138
- catch { }
139
99
  const requested = args.repo_id ?? null;
140
100
  const mismatch = requested ? assertScope(identity.repoId, requested) : null;
141
101
  const memCount = store.prepare("SELECT COUNT(*) as c FROM memories").get().c;
@@ -174,14 +134,6 @@ export function createReadTools(opts) {
174
134
  const mismatch = assertScope(identity.repoId, args.repo_id);
175
135
  if (mismatch)
176
136
  return mismatch;
177
- try {
178
- metrics.incr("mcp_requests_total", 1);
179
- }
180
- catch { }
181
- try {
182
- metrics.incr("mcp_reads_served", 1);
183
- }
184
- catch { }
185
137
  const svc = memService();
186
138
  const memories = svc.getRelevant({ query: args.query, maxTokens: 2500, scope: "all" });
187
139
  return { dry_run: true, results: memories.map((m) => ({ id: m.id, type: m.type, scope: m.scope })), provenance: buildProvenance(identity) };
@@ -195,14 +147,6 @@ export function createReadTools(opts) {
195
147
  const mismatch = assertScope(identity.repoId, args.repo_id);
196
148
  if (mismatch)
197
149
  return mismatch;
198
- try {
199
- metrics.incr("mcp_requests_total", 1);
200
- }
201
- catch { }
202
- try {
203
- metrics.incr("mcp_reads_served", 1);
204
- }
205
- catch { }
206
150
  const fb = new Feedback(store, metrics);
207
151
  try {
208
152
  const id = fb.record({ memoryId: args.id, verdict: args.verdict, sessionId: `mcp:${Date.now()}` });
@@ -31,10 +31,6 @@ export function createWriteTools(opts) {
31
31
  const mismatch = assertScope(identity.repoId, args.repo_id);
32
32
  if (mismatch)
33
33
  return mismatch;
34
- try {
35
- metrics.incr("mcp_requests_total", 1);
36
- }
37
- catch { }
38
34
  if (!isWriteEnabled()) {
39
35
  try {
40
36
  metrics.incr("mcp_writes_refused", 1);
@@ -44,7 +40,7 @@ export function createWriteTools(opts) {
44
40
  }
45
41
  const svc = new MemoryService(store, metrics, identity.repoId);
46
42
  try {
47
- const mem = svc.save({
43
+ const id = svc.save({
48
44
  type: args.type,
49
45
  content: args.content,
50
46
  scope: args.scope ?? "project",
@@ -53,7 +49,7 @@ export function createWriteTools(opts) {
53
49
  metrics.incr("mcp_writes_accepted", 1);
54
50
  }
55
51
  catch { }
56
- return { id: mem.id, provenance: buildProvenance(identity) };
52
+ return { id, provenance: buildProvenance(identity) };
57
53
  }
58
54
  catch (e) {
59
55
  try {
@@ -72,10 +68,6 @@ export function createWriteTools(opts) {
72
68
  const mismatch = assertScope(identity.repoId, args.repo_id);
73
69
  if (mismatch)
74
70
  return mismatch;
75
- try {
76
- metrics.incr("mcp_requests_total", 1);
77
- }
78
- catch { }
79
71
  if (!isWriteEnabled() || !isApproveEnabled()) {
80
72
  try {
81
73
  metrics.incr("mcp_writes_refused", 1);
@@ -111,10 +103,6 @@ export function createWriteTools(opts) {
111
103
  const mismatch = assertScope(identity.repoId, args.repo_id);
112
104
  if (mismatch)
113
105
  return mismatch;
114
- try {
115
- metrics.incr("mcp_requests_total", 1);
116
- }
117
- catch { }
118
106
  if (!isWriteEnabled() || !isApproveEnabled()) {
119
107
  try {
120
108
  metrics.incr("mcp_writes_refused", 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmtrin/kevin-mcp",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Kevin MCP — stdio bridge for any MCP harness (Bridge)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "prepublishOnly": "npm run build"
24
24
  },
25
25
  "dependencies": {
26
- "@jmtrin/kevin-core": "1.4.0",
26
+ "@jmtrin/kevin-core": "1.5.0",
27
27
  "@modelcontextprotocol/sdk": "1.30.0",
28
28
  "zod": "^3.25.0"
29
29
  },