Ollama MCP Server
by rawveg
- ollama-mcp
- src
// src/index.ts
import express from 'express';
import fetch from 'node-fetch';
import type { Request, Response } from 'express';
export class OllamaMCPServer {
private app = express();
private server: any;
private ollamaApi: string;
constructor(ollamaApi: string = 'http://localhost:11434') {
this.ollamaApi = ollamaApi;
this.setupRoutes();
}
private setupRoutes() {
this.app.use(express.json());
this.app.get('/models', this.listModels.bind(this));
this.app.post('/models/pull', this.pullModel.bind(this));
this.app.post('/chat', this.chat.bind(this));
this.app.get('/models/:name', this.getModelInfo.bind(this));
}
private async listModels(req: Request, res: Response) {
try {
const response = await fetch(`${this.ollamaApi}/api/tags`);
const data = await response.json();
res.json(data);
} catch (error) {
res.status(500).json({ error: String(error) });
}
}
private async pullModel(req: Request, res: Response) {
const { name } = req.body;
if (!name) {
return res.status(400).json({ error: 'Model name is required' });
}
try {
const response = await fetch(`${this.ollamaApi}/api/pull`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name })
});
const data = await response.json();
res.json(data);
} catch (error) {
res.status(500).json({ error: String(error) });
}
}
private async chat(req: Request, res: Response) {
const { model, messages } = req.body;
if (!model || !messages) {
return res.status(400).json({ error: 'Model and messages are required' });
}
try {
const response = await fetch(`${this.ollamaApi}/api/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model,
messages,
stream: false
})
});
const data = await response.json();
res.json(data);
} catch (error) {
res.status(500).json({ error: String(error) });
}
}
private async getModelInfo(req: Request, res: Response) {
const { name } = req.params;
try {
const response = await fetch(`${this.ollamaApi}/api/show`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name })
});
const data = await response.json();
res.json(data);
} catch (error) {
res.status(500).json({ error: String(error) });
}
}
public start(port: number = 3456): Promise<void> {
return new Promise((resolve, reject) => {
try {
this.server = this.app.listen(port, () => {
console.log(`Ollama MCP Server running on port ${port}`);
resolve();
});
this.server.on('error', (error: Error & { code?: string }) => {
if (error.code === 'EADDRINUSE') {
reject(new Error(`Port ${port} is already in use`));
} else {
reject(error);
}
});
} catch (error) {
reject(error);
}
});
}
public stop(): Promise<void> {
return new Promise((resolve, reject) => {
if (this.server) {
this.server.close((err?: Error) => {
if (err) reject(err);
else resolve();
});
} else {
resolve();
}
});
}
}
export default OllamaMCPServer;