Аз съм доста пристрастен към последния от нас сериал. Съжалявам за корицата.
MCPs са навсякъде и по добра причина.Това е следващата стъпка в еволюцията на приложенията.
Да можеш да използваш всичко от един чат, без да имаш достъп до което и да е приложение.Постътда планирате всичките си социални постове от чата! Така че започнах да копая в кода на Postiz и добавих към него!
Репозиторията на MCP е малко странна
Всеки MCP има транспорт, който е методът, който LLMs използват, за да говорят с нашата система.
There are two primary methods at the momentStdio, което по същество е командна линия, и SSE.
Не разбирам защо са избрали SSE – това е основно дълго искане, което никога не свършва и предава събития на клиента.
Проблемът с този метод е, че за да изпратите информация обратно на сървъра, трябва да изпратите друго искане за поща (тъй като SSE е еднопосочна комуникация), което означава, че трябва да запазите състоянието.
В примера си те държат състоянието в паметта на приложението и предполагат какво?Много хора се оплакват от изтичане на памет, защото състоянието не се изтрива, когато потребителят се изключи.
Ще използвам WebSockets. Те имат вграден режим на сън и не е нужно да поддържате състояние за него.
Изкопаване на
Изкопах в Anthropic typcript SDK и не бях изненадан. Чувства се грозно. Много неща не се използват в производството, като "Ресурси". Начинът, по който те изискват от вас да запазите всичко глобално в паметта, е бедствие, което чака да се случи.
Също така е трудно да се реализира удостоверяване и да се извади потребителя от контекста, за да можем да получим техните подробности.
Postiz е изграден с NestJS, така че когато използвате маршрут на SSE, той затваря наблюдаваното, след като се изключи, което ви позволява да премахнете всичко от паметта.
import EventEmitter from 'events';
import { finalize, fromEvent, startWith } from 'rxjs';
@Injectable()
export class McpService {
static event = new EventEmitter();
constructor(
private _mainMcp: MainMcp
) {
}
async runServer(apiKey: string, organization: string) {
const server = McpSettings.load(organization, this._mainMcp).server();
const transport = new McpTransport(organization);
const observer = fromEvent(
McpService.event,
`organization-${organization}`
).pipe(
startWith({
type: 'endpoint',
data: process.env.NEXT_PUBLIC_BACKEND_URL + '/mcp/' + apiKey + '/messages',
}),
finalize(() => {
transport.close();
})
);
console.log('MCP transport started');
await server.connect(transport);
return observer;
}
async processPostBody(organization: string, body: object) {
const server = McpSettings.load(organization, this._mainMcp).server();
const message = JSONRPCMessageSchema.parse(body);
const transport = new McpTransport(organization);
await server.connect(transport);
transport.handlePostMessage(message);
return {};
}
}
Декорация ️
Това е за вас, ако сте голям фен на OOP рамки като NestJS/Laravel/Spring. създадох хладен декоратор за създаване на инструменти като API "крайни точки".
@McpTool({ toolName: 'POSTIZ_GET_CONFIG_ID' })
async preRun() {
return [
{
type: 'text',
text: `id: ${makeId(10)} Today date is ${dayjs.utc().format()}`,
},
];
}
@McpTool({ toolName: 'POSTIZ_PROVIDERS_LIST' })
async listOfProviders(organization: string) {
const list = (
await this._integrationService.getIntegrationsList(organization)
).map((org) => ({
id: org.id,
name: org.name,
identifier: org.providerIdentifier,
picture: org.picture,
disabled: org.disabled,
profile: org.profile,
customer: org.customer
? {
id: org.customer.id,
name: org.customer.name,
}
: undefined,
}));
return [{ type: 'text', text: JSON.stringify(list) }];
}
@McpTool({
toolName: 'POSTIZ_SCHEDULE_POST',
zod: {
type: eenum(['draft', 'scheduled']),
configId: string(),
generatePictures: boolean(),
date: string().describe('UTC TIME'),
providerId: string().describe('Use POSTIZ_PROVIDERS_LIST to get the id'),
posts: array(object({ text: string(), images: array(string()) })),
},
})
async schedulePost(
organization: string,
obj: {
type: 'draft' | 'schedule';
generatePictures: boolean;
date: string;
providerId: string;
posts: { text: string }[];
}
) {
const create = await this._postsService.createPost(organization, {
date: obj.date,
type: obj.type,
tags: [],
posts: [
{
group: makeId(10),
value: await Promise.all(
obj.posts.map(async (post) => ({
content: post.text,
id: makeId(10),
image: !obj.generatePictures
? []
: [
{
id: makeId(10),
path: await this._openAiService.generateImage(
post.text,
true
),
},
],
}))
),
// @ts-ignore
settings: {},
integration: {
id: obj.providerId,
},
},
],
});
return [
{
type: 'text',
text: `Post created successfully, check it here: ${process.env.FRONTEND_URL}/p/${create[0].postId}`,
},
];
}
Целият код може да бъде намерен в Postiz тук:https://github.com/gitroomhq/postiz-app/tree/main/libraries/nestjs-libraries/src/mcp
И тук:https://github.com/gitroomhq/postiz-app/tree/main/apps/backend/src/mcp
Накарайте LLM да направи нещата 🙏🏻
Би било хубаво да имаме вградена опция, за да принудим LLM да прави различни неща, преди да получи достъп до нашите неща.
Всеки път, когато казах на Cursor да планира пост за мен, той се опита да го планира за 2024 г. Това е последният път, когато моделът беше обучен.
Трябваше да премина някои конфиг детайли, така че създадохPOSTIZ_CONFIGURATION_PRERUN
Надявам се, че LLM винаги ще го нарича, преди да направи нещо.
Но тя го игнорира много пъти (типично), така че трябваше да бъда творчески.POSTIZ_SCHEDULE_POST
, добавих нова собственост, нареченаconfigId
и променете името на инструмента Config наPOSTIZ_GET_CONFIG_ID.
Резултатът от конфигурацията е:id: ${makeId(10)} Today date is ${dayjs.utc().format()}
Това принуди LLM винаги да го нарича по-рано, а датата беше фиксирана! :)
Това беше още по-добре за мен, защото знаех, че ще ми изпрати UTC дати отсега нататък.
Случаи на употреба
Мисля, че тя работи най-добре, когато се комбинира с няколко набора от инструменти, например:
- на
- Свържете го с курсора и го помолете да планира публикация за вашата работа днес. на
- Свържете го с Notion и поискайте да планирате цялата последна работа на екипа в социалните медии - вижте Composio MCPs. на
- Свържете го с всяка SaaS, която има CopilotKit и планирайте публикации въз основа на приложението. на
Създаване на MCP
Постъте най-трайният инструмент за планиране на социални медии с отворен код - и сега единственият графика, който предлага MCP (натурално, не със Zapier или нещо подобно)
С новия MCP можете да планирате всичките си публикации от клиентите Cursor/Windsurf и Anthropic.
Всичко е 100% безплатно :)
Ако ви харесва, не забравяйте да ни звезда ⭐️https://github.com/gitroomhq/postiz-апп