adding an MCP Server 🎉

This commit is contained in:
orangecoding
2026-03-09 15:35:29 +01:00
parent a460b813c1
commit be5c4af3cf
21 changed files with 1374 additions and 51 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -1,20 +1,11 @@
{
"key": "00e6b81777a275f5a140fc9101cb943810db6a69f6eb3927319c5aee0c876510",
"key": "00e6b81777a275f5a140fc9101cb943810db6a69f6eb3927319c5aee0c876511",
"content":
[
{
"title": "Listings can now be filtered by location",
"text": "Thanks to https://github.com/strech345 for adding a new feature that allows you to filter listings based on their their location. When creating a job, you can now create multiple areas in which Fredy searches for new listings",
"image": "1.png"
},
{
"title": "More details from the Immoscout Provider",
"text": "https://github.com/MindCollaps added a new user-setting. When enabled Fredy will pull way more information for each listing from Immoscout.",
"image": "2.png"
},
{
"title": "Listings now marked as invisible if filtered",
"text": "So far, when a listing was filtered e.g. due to being a duplicate, it was not send to you, but still shown on the map. This was now fixed."
"title": "Fredy goes AI",
"text": "With Fredy v20.0.0, we are introducing Fredys own MCP server. This brings a powerful new capability: you can connect your local LLM directly to Fredy and explore the data it collects in a much more flexible way.<br/><br/>The MCP server exposes Fredys tools and findings through a structured interface, allowing your LLM to query listings, inspect collected details, and analyze results programmatically. Instead of manually searching through the data, you can simply ask your model questions and let it dig into what Fredy has discovered for you.<br/><br/>In practice, this means your local LLM can interact with Fredy almost like an assistant: investigating properties, summarizing listings, filtering results, or helping you identify interesting opportunities based on the data Fredy gathered.",
"media": "news.mp4"
}
]
}

BIN
ui/src/assets/news/news.mp4 Normal file

Binary file not shown.

View File

@@ -11,7 +11,7 @@ import { useActions, useSelector } from '../../services/state/store';
import './NewsModal.less';
const newsImages = import.meta.glob('../../assets/news/*', { eager: true, query: '?url', import: 'default' });
const newsMedia = import.meta.glob('../../assets/news/*', { eager: true, query: '?url', import: 'default' });
const NewsModal = () => {
const screenWidth = useScreenWidth();
@@ -20,7 +20,7 @@ const NewsModal = () => {
const pois = useSelector((state) => state.tracking.pois);
const actions = useActions();
if (newsConfig == null || newsConfig.length === 0 || screenWidth <= 768) {
if (newsConfig == null || newsConfig.content == null || newsConfig.content.length === 0 || screenWidth <= 768) {
return null;
}
@@ -33,13 +33,20 @@ const NewsModal = () => {
),
description: (
<div style={{ textAlign: 'left' }}>
{item.image && newsImages[`../../assets/news/${item.image}`] && (
<img
src={newsImages[`../../assets/news/${item.image}`]}
alt={item.title}
style={{ width: '100%', marginBottom: 10, borderRadius: 4 }}
/>
)}
{item.media &&
newsMedia[`../../assets/news/${item.media}`] &&
(item.media.includes('mp4') ? (
<video controls width="500">
<source src={newsMedia[`../../assets/news/${item.media}`]} type="video/mp4" />
Your browser does not support the video tag.
</video>
) : (
<img
src={newsMedia[`../../assets/news/${item.media}`]}
alt={item.title}
style={{ width: '100%', marginBottom: 10, borderRadius: 4 }}
/>
))}
<p dangerouslySetInnerHTML={{ __html: item.text }} />
</div>
),
@@ -61,7 +68,7 @@ const NewsModal = () => {
onFinish={() => handleClose(pois.WELCOME_FINISHED)}
onSkip={() => handleClose(pois.WELCOME_SKIPPED)}
modalProps={{
width: '10rem',
width: '850px',
}}
/>
);

View File

@@ -37,6 +37,17 @@ export default function UserTable({ user = [], onUserRemoval, onUserEdit } = {})
title: 'Number of jobs',
dataIndex: 'numberOfJobs',
},
{
title: 'MCP Token',
dataIndex: 'mcpToken',
render: (value) => {
return (
<span style={{ fontFamily: 'monospace', fontSize: '0.85em', wordBreak: 'break-all' }}>
{value || '---'}
</span>
);
},
},
{
title: '',
dataIndex: 'tools',