@tmhs/local-ai-mcp 0.1.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.
Files changed (60) hide show
  1. package/LICENSE +34 -0
  2. package/README.md +126 -0
  3. package/dist/catalog/models.d.ts +11 -0
  4. package/dist/catalog/models.js +114 -0
  5. package/dist/catalog/models.js.map +1 -0
  6. package/dist/config.d.ts +7 -0
  7. package/dist/config.js +22 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/hardware/index.d.ts +16 -0
  10. package/dist/hardware/index.js +30 -0
  11. package/dist/hardware/index.js.map +1 -0
  12. package/dist/hardware/linux.d.ts +2 -0
  13. package/dist/hardware/linux.js +48 -0
  14. package/dist/hardware/linux.js.map +1 -0
  15. package/dist/hardware/windows.d.ts +2 -0
  16. package/dist/hardware/windows.js +60 -0
  17. package/dist/hardware/windows.js.map +1 -0
  18. package/dist/http.d.ts +14 -0
  19. package/dist/http.js +61 -0
  20. package/dist/http.js.map +1 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +24 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/providers/lmstudio.d.ts +44 -0
  25. package/dist/providers/lmstudio.js +181 -0
  26. package/dist/providers/lmstudio.js.map +1 -0
  27. package/dist/providers/manager.d.ts +9 -0
  28. package/dist/providers/manager.js +31 -0
  29. package/dist/providers/manager.js.map +1 -0
  30. package/dist/providers/ollama.d.ts +34 -0
  31. package/dist/providers/ollama.js +157 -0
  32. package/dist/providers/ollama.js.map +1 -0
  33. package/dist/providers/types.d.ts +102 -0
  34. package/dist/providers/types.js +2 -0
  35. package/dist/providers/types.js.map +1 -0
  36. package/dist/tools/catalog.d.ts +3 -0
  37. package/dist/tools/catalog.js +55 -0
  38. package/dist/tools/catalog.js.map +1 -0
  39. package/dist/tools/context.d.ts +8 -0
  40. package/dist/tools/context.js +2 -0
  41. package/dist/tools/context.js.map +1 -0
  42. package/dist/tools/delegation.d.ts +3 -0
  43. package/dist/tools/delegation.js +54 -0
  44. package/dist/tools/delegation.js.map +1 -0
  45. package/dist/tools/discovery.d.ts +3 -0
  46. package/dist/tools/discovery.js +61 -0
  47. package/dist/tools/discovery.js.map +1 -0
  48. package/dist/tools/helpers.d.ts +42 -0
  49. package/dist/tools/helpers.js +83 -0
  50. package/dist/tools/helpers.js.map +1 -0
  51. package/dist/tools/index.d.ts +3 -0
  52. package/dist/tools/index.js +13 -0
  53. package/dist/tools/index.js.map +1 -0
  54. package/dist/tools/lifecycle.d.ts +3 -0
  55. package/dist/tools/lifecycle.js +66 -0
  56. package/dist/tools/lifecycle.js.map +1 -0
  57. package/dist/tools/ops.d.ts +12 -0
  58. package/dist/tools/ops.js +113 -0
  59. package/dist/tools/ops.js.map +1 -0
  60. package/package.json +54 -0
@@ -0,0 +1,44 @@
1
+ import type { CompletionParams, CompletionResult, EmbedParams, EmbedResult, HealthStatus, LoadedModelInfo, ModelDetail, ModelSummary, Provider, ProviderCapabilities, PullResult } from "./types.js";
2
+ declare const PROVIDER: "lmstudio";
3
+ export interface CliResult {
4
+ status: number;
5
+ stdout: string;
6
+ stderr: string;
7
+ }
8
+ export type CliRunner = (args: string[]) => CliResult;
9
+ export declare class LMStudioProvider implements Provider {
10
+ readonly id: "lmstudio";
11
+ readonly host: string;
12
+ private cliRunner;
13
+ private lmsAvailableCache;
14
+ constructor(host: string, cliRunner?: CliRunner);
15
+ lmsAvailable(): boolean;
16
+ capabilities(): ProviderCapabilities;
17
+ detect(timeoutMs: number): Promise<boolean>;
18
+ health(timeoutMs: number): Promise<HealthStatus>;
19
+ private mapModel;
20
+ listModels(timeoutMs: number): Promise<ModelSummary[]>;
21
+ listLoaded(timeoutMs: number): Promise<LoadedModelInfo[]>;
22
+ modelInfo(model: string, timeoutMs: number): Promise<ModelDetail>;
23
+ pull(model: string, _timeoutMs: number): Promise<PullResult>;
24
+ remove(model: string, _timeoutMs: number): Promise<{
25
+ provider: typeof PROVIDER;
26
+ model: string;
27
+ removed: boolean;
28
+ }>;
29
+ load(model: string, _timeoutMs: number, _keepAlive?: string): Promise<{
30
+ provider: typeof PROVIDER;
31
+ model: string;
32
+ loaded: boolean;
33
+ detail?: string;
34
+ }>;
35
+ unload(model: string, _timeoutMs: number): Promise<{
36
+ provider: typeof PROVIDER;
37
+ model: string;
38
+ unloaded: boolean;
39
+ detail?: string;
40
+ }>;
41
+ complete(params: CompletionParams, timeoutMs: number): Promise<CompletionResult>;
42
+ embed(params: EmbedParams, timeoutMs: number): Promise<EmbedResult>;
43
+ }
44
+ export {};
@@ -0,0 +1,181 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { httpJson, probe } from "../http.js";
3
+ const PROVIDER = "lmstudio";
4
+ function defaultCliRunner(args) {
5
+ const res = spawnSync("lms", args, { encoding: "utf8" });
6
+ return {
7
+ status: res.status ?? (res.error ? 1 : 0),
8
+ stdout: res.stdout ?? "",
9
+ stderr: res.stderr ?? (res.error ? String(res.error.message) : ""),
10
+ };
11
+ }
12
+ export class LMStudioProvider {
13
+ id = PROVIDER;
14
+ host;
15
+ cliRunner;
16
+ lmsAvailableCache;
17
+ constructor(host, cliRunner = defaultCliRunner) {
18
+ this.host = host;
19
+ this.cliRunner = cliRunner;
20
+ }
21
+ lmsAvailable() {
22
+ if (this.lmsAvailableCache === undefined) {
23
+ try {
24
+ this.lmsAvailableCache = this.cliRunner(["version"]).status === 0;
25
+ }
26
+ catch {
27
+ this.lmsAvailableCache = false;
28
+ }
29
+ }
30
+ return this.lmsAvailableCache;
31
+ }
32
+ capabilities() {
33
+ const cli = this.lmsAvailable();
34
+ return {
35
+ provider: PROVIDER,
36
+ complete: true,
37
+ embed: true,
38
+ pull: cli,
39
+ remove: cli,
40
+ load: cli,
41
+ unload: cli,
42
+ search: false,
43
+ };
44
+ }
45
+ async detect(timeoutMs) {
46
+ if (await probe(`${this.host}/api/v0/models`, timeoutMs))
47
+ return true;
48
+ return probe(`${this.host}/v1/models`, timeoutMs);
49
+ }
50
+ async health(timeoutMs) {
51
+ const live = await this.detect(timeoutMs);
52
+ return live
53
+ ? { provider: PROVIDER, live: true, host: this.host }
54
+ : {
55
+ provider: PROVIDER,
56
+ live: false,
57
+ host: this.host,
58
+ error: "LM Studio server not reachable",
59
+ };
60
+ }
61
+ mapModel(m) {
62
+ return {
63
+ id: m.id,
64
+ provider: PROVIDER,
65
+ family: m.arch,
66
+ quantization: m.quantization,
67
+ };
68
+ }
69
+ async listModels(timeoutMs) {
70
+ const data = await httpJson(`${this.host}/api/v0/models`, {
71
+ timeoutMs,
72
+ });
73
+ return (data.data ?? []).map((m) => this.mapModel(m));
74
+ }
75
+ async listLoaded(timeoutMs) {
76
+ const data = await httpJson(`${this.host}/api/v0/models`, {
77
+ timeoutMs,
78
+ });
79
+ return (data.data ?? [])
80
+ .filter((m) => m.state === "loaded")
81
+ .map((m) => ({
82
+ id: m.id,
83
+ provider: PROVIDER,
84
+ contextLength: m.loaded_context_length ?? m.max_context_length,
85
+ }));
86
+ }
87
+ async modelInfo(model, timeoutMs) {
88
+ const m = await httpJson(`${this.host}/api/v0/models/${encodeURIComponent(model)}`, { timeoutMs });
89
+ return {
90
+ id: m.id ?? model,
91
+ provider: PROVIDER,
92
+ family: m.arch,
93
+ quantization: m.quantization,
94
+ contextLength: m.max_context_length,
95
+ details: m,
96
+ };
97
+ }
98
+ async pull(model, _timeoutMs) {
99
+ if (!this.lmsAvailable()) {
100
+ throw new Error("LM Studio pull requires the lms CLI");
101
+ }
102
+ const res = this.cliRunner(["get", model]);
103
+ if (res.status !== 0) {
104
+ throw new Error(`lms get failed: ${res.stderr || res.stdout}`);
105
+ }
106
+ return { provider: PROVIDER, model, status: "success" };
107
+ }
108
+ async remove(model, _timeoutMs) {
109
+ if (!this.lmsAvailable()) {
110
+ throw new Error("LM Studio remove requires the lms CLI");
111
+ }
112
+ const res = this.cliRunner(["rm", model]);
113
+ if (res.status !== 0) {
114
+ throw new Error(`lms rm failed: ${res.stderr || res.stdout}`);
115
+ }
116
+ return { provider: PROVIDER, model, removed: true };
117
+ }
118
+ async load(model, _timeoutMs, _keepAlive) {
119
+ if (this.lmsAvailable()) {
120
+ const res = this.cliRunner(["load", model]);
121
+ if (res.status !== 0) {
122
+ throw new Error(`lms load failed: ${res.stderr || res.stdout}`);
123
+ }
124
+ return { provider: PROVIDER, model, loaded: true };
125
+ }
126
+ return {
127
+ provider: PROVIDER,
128
+ model,
129
+ loaded: true,
130
+ detail: "LM Studio loads on first request (JIT); no CLI present",
131
+ };
132
+ }
133
+ async unload(model, _timeoutMs) {
134
+ if (!this.lmsAvailable()) {
135
+ throw new Error("LM Studio unload requires the lms CLI; install it to unload models");
136
+ }
137
+ const res = this.cliRunner(["unload", model]);
138
+ if (res.status !== 0) {
139
+ throw new Error(`lms unload failed: ${res.stderr || res.stdout}`);
140
+ }
141
+ return { provider: PROVIDER, model, unloaded: true };
142
+ }
143
+ async complete(params, timeoutMs) {
144
+ const messages = params.messages ?? [{ role: "user", content: params.prompt ?? "" }];
145
+ const start = Date.now();
146
+ const data = await httpJson(`${this.host}/v1/chat/completions`, {
147
+ method: "POST",
148
+ body: JSON.stringify({
149
+ model: params.model,
150
+ messages,
151
+ max_tokens: params.maxTokens,
152
+ temperature: params.temperature,
153
+ stop: params.stop,
154
+ }),
155
+ timeoutMs,
156
+ });
157
+ return {
158
+ provider: PROVIDER,
159
+ model: params.model,
160
+ text: data.choices?.[0]?.message?.content ?? "",
161
+ promptTokens: data.usage?.prompt_tokens,
162
+ completionTokens: data.usage?.completion_tokens,
163
+ totalDurationMs: Date.now() - start,
164
+ };
165
+ }
166
+ async embed(params, timeoutMs) {
167
+ const data = await httpJson(`${this.host}/v1/embeddings`, {
168
+ method: "POST",
169
+ body: JSON.stringify({ model: params.model, input: params.input }),
170
+ timeoutMs,
171
+ });
172
+ const embeddings = (data.data ?? []).map((d) => d.embedding);
173
+ return {
174
+ provider: PROVIDER,
175
+ model: params.model,
176
+ embeddings,
177
+ dimensions: embeddings[0]?.length ?? 0,
178
+ };
179
+ }
180
+ }
181
+ //# sourceMappingURL=lmstudio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lmstudio.js","sourceRoot":"","sources":["../../src/providers/lmstudio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Config } from "../config.js";
2
+ import type { Provider } from "./types.js";
3
+ export declare class ProviderManager {
4
+ readonly providers: Provider[];
5
+ constructor(config: Config);
6
+ get(id: string): Provider | undefined;
7
+ detected(timeoutMs: number): Promise<Provider[]>;
8
+ resolve(providerArg: string | undefined, timeoutMs: number): Promise<Provider[]>;
9
+ }
@@ -0,0 +1,31 @@
1
+ import { LMStudioProvider } from "./lmstudio.js";
2
+ import { OllamaProvider } from "./ollama.js";
3
+ export class ProviderManager {
4
+ providers;
5
+ constructor(config) {
6
+ this.providers = [
7
+ new OllamaProvider(config.ollamaHost),
8
+ new LMStudioProvider(config.lmstudioHost),
9
+ ];
10
+ }
11
+ get(id) {
12
+ return this.providers.find((p) => p.id === id);
13
+ }
14
+ async detected(timeoutMs) {
15
+ const results = await Promise.all(this.providers.map(async (p) => ({ provider: p, live: await p.detect(timeoutMs) })));
16
+ return results.filter((r) => r.live).map((r) => r.provider);
17
+ }
18
+ async resolve(providerArg, timeoutMs) {
19
+ if (providerArg) {
20
+ const p = this.get(providerArg);
21
+ if (!p) {
22
+ throw new Error(`Unknown provider: ${providerArg}. Known providers: ${this.providers
23
+ .map((x) => x.id)
24
+ .join(", ")}`);
25
+ }
26
+ return [p];
27
+ }
28
+ return this.detected(timeoutMs);
29
+ }
30
+ }
31
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/providers/manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,OAAO,eAAe;IACjB,SAAS,CAAa;IAE/B,YAAY,MAAc;QACxB,IAAI,CAAC,SAAS,GAAG;YACf,IAAI,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC;YACrC,IAAI,gBAAgB,CAAC,MAAM,CAAC,YAAY,CAAC;SAC1C,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAM,EAAiB,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,SAAiB;QAC9B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CACpF,CAAC;QACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,WAA+B,EAAE,SAAiB;QAC9D,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAChC,IAAI,CAAC,CAAC,EAAE,CAAC;gBACP,MAAM,IAAI,KAAK,CACb,qBAAqB,WAAW,sBAAsB,IAAI,CAAC,SAAS;qBACjE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAChB,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,CAAC,CAAC,CAAC;QACb,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ import type { CompletionParams, CompletionResult, EmbedParams, EmbedResult, HealthStatus, LoadedModelInfo, ModelDetail, ModelSummary, Provider, ProviderCapabilities, PullResult } from "./types.js";
2
+ declare const PROVIDER: "ollama";
3
+ export declare class OllamaProvider implements Provider {
4
+ readonly id: "ollama";
5
+ readonly host: string;
6
+ constructor(host: string);
7
+ capabilities(): ProviderCapabilities;
8
+ detect(timeoutMs: number): Promise<boolean>;
9
+ health(timeoutMs: number): Promise<HealthStatus>;
10
+ listModels(timeoutMs: number): Promise<ModelSummary[]>;
11
+ listLoaded(timeoutMs: number): Promise<LoadedModelInfo[]>;
12
+ modelInfo(model: string, timeoutMs: number): Promise<ModelDetail>;
13
+ pull(model: string, timeoutMs: number): Promise<PullResult>;
14
+ remove(model: string, timeoutMs: number): Promise<{
15
+ provider: typeof PROVIDER;
16
+ model: string;
17
+ removed: boolean;
18
+ }>;
19
+ load(model: string, timeoutMs: number, keepAlive?: string): Promise<{
20
+ provider: typeof PROVIDER;
21
+ model: string;
22
+ loaded: boolean;
23
+ detail?: string;
24
+ }>;
25
+ unload(model: string, timeoutMs: number): Promise<{
26
+ provider: typeof PROVIDER;
27
+ model: string;
28
+ unloaded: boolean;
29
+ detail?: string;
30
+ }>;
31
+ complete(params: CompletionParams, timeoutMs: number): Promise<CompletionResult>;
32
+ embed(params: EmbedParams, timeoutMs: number): Promise<EmbedResult>;
33
+ }
34
+ export {};
@@ -0,0 +1,157 @@
1
+ import { httpJson, probe } from "../http.js";
2
+ const PROVIDER = "ollama";
3
+ export class OllamaProvider {
4
+ id = PROVIDER;
5
+ host;
6
+ constructor(host) {
7
+ this.host = host;
8
+ }
9
+ capabilities() {
10
+ return {
11
+ provider: PROVIDER,
12
+ complete: true,
13
+ embed: true,
14
+ pull: true,
15
+ remove: true,
16
+ load: true,
17
+ unload: true,
18
+ search: false,
19
+ };
20
+ }
21
+ async detect(timeoutMs) {
22
+ return probe(`${this.host}/api/version`, timeoutMs);
23
+ }
24
+ async health(timeoutMs) {
25
+ try {
26
+ const data = await httpJson(`${this.host}/api/version`, { timeoutMs });
27
+ return { provider: PROVIDER, live: true, host: this.host, version: data.version };
28
+ }
29
+ catch (err) {
30
+ return {
31
+ provider: PROVIDER,
32
+ live: false,
33
+ host: this.host,
34
+ error: err instanceof Error ? err.message : String(err),
35
+ };
36
+ }
37
+ }
38
+ async listModels(timeoutMs) {
39
+ const data = await httpJson(`${this.host}/api/tags`, {
40
+ timeoutMs,
41
+ });
42
+ return (data.models ?? []).map((m) => ({
43
+ id: m.name,
44
+ provider: PROVIDER,
45
+ sizeBytes: m.size,
46
+ family: m.details?.family,
47
+ parameterSize: m.details?.parameter_size,
48
+ quantization: m.details?.quantization_level,
49
+ modifiedAt: m.modified_at,
50
+ }));
51
+ }
52
+ async listLoaded(timeoutMs) {
53
+ const data = await httpJson(`${this.host}/api/ps`, { timeoutMs });
54
+ return (data.models ?? []).map((m) => ({
55
+ id: m.name,
56
+ provider: PROVIDER,
57
+ sizeVramBytes: m.size_vram,
58
+ expiresAt: m.expires_at,
59
+ contextLength: m.context_length,
60
+ }));
61
+ }
62
+ async modelInfo(model, timeoutMs) {
63
+ const data = await httpJson(`${this.host}/api/show`, {
64
+ method: "POST",
65
+ body: JSON.stringify({ model }),
66
+ timeoutMs,
67
+ });
68
+ let contextLength;
69
+ if (data.model_info) {
70
+ for (const [key, value] of Object.entries(data.model_info)) {
71
+ if (key.endsWith(".context_length") && typeof value === "number") {
72
+ contextLength = value;
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ return {
78
+ id: model,
79
+ provider: PROVIDER,
80
+ family: data.details?.family,
81
+ parameterSize: data.details?.parameter_size,
82
+ quantization: data.details?.quantization_level,
83
+ contextLength,
84
+ details: data.details,
85
+ };
86
+ }
87
+ async pull(model, timeoutMs) {
88
+ const data = await httpJson(`${this.host}/api/pull`, {
89
+ method: "POST",
90
+ body: JSON.stringify({ model, stream: false }),
91
+ timeoutMs,
92
+ });
93
+ return { provider: PROVIDER, model, status: data.status ?? "success" };
94
+ }
95
+ async remove(model, timeoutMs) {
96
+ await httpJson(`${this.host}/api/delete`, {
97
+ method: "DELETE",
98
+ body: JSON.stringify({ model }),
99
+ timeoutMs,
100
+ });
101
+ return { provider: PROVIDER, model, removed: true };
102
+ }
103
+ async load(model, timeoutMs, keepAlive) {
104
+ await httpJson(`${this.host}/api/generate`, {
105
+ method: "POST",
106
+ body: JSON.stringify({ model, prompt: "", keep_alive: keepAlive ?? "5m" }),
107
+ timeoutMs,
108
+ });
109
+ return { provider: PROVIDER, model, loaded: true };
110
+ }
111
+ async unload(model, timeoutMs) {
112
+ await httpJson(`${this.host}/api/generate`, {
113
+ method: "POST",
114
+ body: JSON.stringify({ model, prompt: "", keep_alive: 0 }),
115
+ timeoutMs,
116
+ });
117
+ return { provider: PROVIDER, model, unloaded: true };
118
+ }
119
+ async complete(params, timeoutMs) {
120
+ const messages = params.messages ?? [{ role: "user", content: params.prompt ?? "" }];
121
+ const start = Date.now();
122
+ const data = await httpJson(`${this.host}/v1/chat/completions`, {
123
+ method: "POST",
124
+ body: JSON.stringify({
125
+ model: params.model,
126
+ messages,
127
+ max_tokens: params.maxTokens,
128
+ temperature: params.temperature,
129
+ stop: params.stop,
130
+ }),
131
+ timeoutMs,
132
+ });
133
+ return {
134
+ provider: PROVIDER,
135
+ model: params.model,
136
+ text: data.choices?.[0]?.message?.content ?? "",
137
+ promptTokens: data.usage?.prompt_tokens,
138
+ completionTokens: data.usage?.completion_tokens,
139
+ totalDurationMs: Date.now() - start,
140
+ };
141
+ }
142
+ async embed(params, timeoutMs) {
143
+ const data = await httpJson(`${this.host}/v1/embeddings`, {
144
+ method: "POST",
145
+ body: JSON.stringify({ model: params.model, input: params.input }),
146
+ timeoutMs,
147
+ });
148
+ const embeddings = (data.data ?? []).map((d) => d.embedding);
149
+ return {
150
+ provider: PROVIDER,
151
+ model: params.model,
152
+ embeddings,
153
+ dimensions: embeddings[0]?.length ?? 0,
154
+ };
155
+ }
156
+ }
157
+ //# sourceMappingURL=ollama.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/providers/ollama.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ export type ProviderId = "ollama" | "lmstudio";
2
+ export interface ModelSummary {
3
+ id: string;
4
+ provider: ProviderId;
5
+ sizeBytes?: number;
6
+ family?: string;
7
+ parameterSize?: string;
8
+ quantization?: string;
9
+ modifiedAt?: string;
10
+ }
11
+ export interface LoadedModelInfo {
12
+ id: string;
13
+ provider: ProviderId;
14
+ sizeVramBytes?: number;
15
+ expiresAt?: string;
16
+ contextLength?: number;
17
+ }
18
+ export interface ModelDetail extends ModelSummary {
19
+ contextLength?: number;
20
+ details?: Record<string, unknown>;
21
+ }
22
+ export interface CompletionParams {
23
+ model: string;
24
+ prompt?: string;
25
+ messages?: Array<{
26
+ role: string;
27
+ content: string;
28
+ }>;
29
+ maxTokens?: number;
30
+ temperature?: number;
31
+ stop?: string[];
32
+ }
33
+ export interface CompletionResult {
34
+ provider: ProviderId;
35
+ model: string;
36
+ text: string;
37
+ promptTokens?: number;
38
+ completionTokens?: number;
39
+ totalDurationMs?: number;
40
+ }
41
+ export interface EmbedParams {
42
+ model: string;
43
+ input: string | string[];
44
+ }
45
+ export interface EmbedResult {
46
+ provider: ProviderId;
47
+ model: string;
48
+ embeddings: number[][];
49
+ dimensions: number;
50
+ }
51
+ export interface HealthStatus {
52
+ provider: ProviderId;
53
+ live: boolean;
54
+ host: string;
55
+ version?: string;
56
+ error?: string;
57
+ }
58
+ export interface ProviderCapabilities {
59
+ provider: ProviderId;
60
+ complete: boolean;
61
+ embed: boolean;
62
+ pull: boolean;
63
+ remove: boolean;
64
+ load: boolean;
65
+ unload: boolean;
66
+ search: boolean;
67
+ }
68
+ export interface PullResult {
69
+ provider: ProviderId;
70
+ model: string;
71
+ status: string;
72
+ }
73
+ export interface Provider {
74
+ readonly id: ProviderId;
75
+ readonly host: string;
76
+ capabilities(): ProviderCapabilities;
77
+ detect(timeoutMs: number): Promise<boolean>;
78
+ health(timeoutMs: number): Promise<HealthStatus>;
79
+ listModels(timeoutMs: number): Promise<ModelSummary[]>;
80
+ listLoaded(timeoutMs: number): Promise<LoadedModelInfo[]>;
81
+ modelInfo(model: string, timeoutMs: number): Promise<ModelDetail>;
82
+ pull(model: string, timeoutMs: number): Promise<PullResult>;
83
+ remove(model: string, timeoutMs: number): Promise<{
84
+ provider: ProviderId;
85
+ model: string;
86
+ removed: boolean;
87
+ }>;
88
+ load(model: string, timeoutMs: number, keepAlive?: string): Promise<{
89
+ provider: ProviderId;
90
+ model: string;
91
+ loaded: boolean;
92
+ detail?: string;
93
+ }>;
94
+ unload(model: string, timeoutMs: number): Promise<{
95
+ provider: ProviderId;
96
+ model: string;
97
+ unloaded: boolean;
98
+ detail?: string;
99
+ }>;
100
+ complete(params: CompletionParams, timeoutMs: number): Promise<CompletionResult>;
101
+ embed(params: EmbedParams, timeoutMs: number): Promise<EmbedResult>;
102
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ToolContext } from "./context.js";
3
+ export declare function register(server: McpServer, ctx: ToolContext): void;
@@ -0,0 +1,55 @@
1
+ import { z } from "zod";
2
+ import { CATALOG, searchCatalog } from "../catalog/models.js";
3
+ import { computeFit, errMsg, fail, ok } from "./helpers.js";
4
+ const TASKS = ["chat", "code", "embed", "vision", "reasoning", "general"];
5
+ export function register(server, ctx) {
6
+ const { hardware } = ctx;
7
+ server.tool("search_available", "Search the built-in catalog of well-known local models by name, family, or task. Note: this searches a curated static catalog, not the full live Ollama library (https://ollama.com/library).", { query: z.string().describe("Search text matched against model name, family, and tasks") }, async ({ query }) => {
8
+ try {
9
+ const matches = searchCatalog(query).map((m) => ({ ...m }));
10
+ return ok({
11
+ query,
12
+ note: "Curated static catalog. For the full set, browse the Ollama library.",
13
+ results: matches,
14
+ });
15
+ }
16
+ catch (err) {
17
+ return fail(errMsg(err));
18
+ }
19
+ });
20
+ server.tool("suggest_model", "Recommend local models for a task (chat/code/embed/vision/reasoning/general), ranked by task match and then by whether they fit the detected free GPU VRAM or system RAM. Returns a ranked list with fit flags.", {
21
+ task: z.enum(TASKS).describe("The task you want a model for"),
22
+ }, async ({ task }) => {
23
+ try {
24
+ const resources = await hardware.getSystemResources();
25
+ const ranked = CATALOG.map((m) => {
26
+ const taskMatch = m.tasks.includes(task);
27
+ const fit = computeFit(resources, m.approxSizeBytes);
28
+ return {
29
+ name: m.name,
30
+ family: m.family,
31
+ parameterSize: m.parameterSize,
32
+ quantization: m.quantization,
33
+ approxSizeBytes: m.approxSizeBytes,
34
+ tasks: m.tasks,
35
+ taskMatch,
36
+ fits: fit.fits,
37
+ fitTarget: fit.target,
38
+ };
39
+ })
40
+ .sort((a, b) => {
41
+ if (a.taskMatch !== b.taskMatch)
42
+ return a.taskMatch ? -1 : 1;
43
+ if (a.fits !== b.fits)
44
+ return a.fits ? -1 : 1;
45
+ return a.approxSizeBytes - b.approxSizeBytes;
46
+ })
47
+ .filter((m) => m.taskMatch);
48
+ return ok({ task, suggestions: ranked });
49
+ }
50
+ catch (err) {
51
+ return fail(errMsg(err));
52
+ }
53
+ });
54
+ }
55
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/tools/catalog.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAG5D,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAU,CAAC;AAEnF,MAAM,UAAU,QAAQ,CAAC,MAAiB,EAAE,GAAgB;IAC1D,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;IAEzB,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,+LAA+L,EAC/L,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC,EAAE,EAC3F,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC5D,OAAO,EAAE,CAAC;gBACR,KAAK;gBACL,IAAI,EAAE,sEAAsE;gBAC5E,OAAO,EAAE,OAAO;aACjB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,iNAAiN,EACjN;QACE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;KAC9D,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,kBAAkB,EAAE,CAAC;YACtD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC/B,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACzC,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC;gBACrD,OAAO;oBACL,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,aAAa,EAAE,CAAC,CAAC,aAAa;oBAC9B,YAAY,EAAE,CAAC,CAAC,YAAY;oBAC5B,eAAe,EAAE,CAAC,CAAC,eAAe;oBAClC,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,SAAS;oBACT,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,SAAS,EAAE,GAAG,CAAC,MAAM;iBACtB,CAAC;YACJ,CAAC,CAAC;iBACC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACb,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS;oBAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7D,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;oBAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9C,OAAO,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,eAAe,CAAC;YAC/C,CAAC,CAAC;iBACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC9B,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}