אני די מכור לסדרה האחרונה שלנו.אני מתנצל על הכיסוי.
MCPs נמצאים בכל מקום ומסיבה טובה.זה הצעד הבא בהתפתחות האפליקציות.
להיות מסוגל להשתמש בכל דבר מתוך צ'אט אחד מבלי לגשת לכל אפליקציה.פוסטיםכדי לתזמן את כל הפוסטים החברתיים שלך מן הצ'אט! אז, התחלתי לחפור לתוך קוד Postiz ולהוסיף אליו!
MCP Repository הוא קצת מוזר
לכל MCP יש תחבורה, שהיא השיטה שבה LLMs להשתמש כדי לדבר עם המערכת שלנו.
There are two primary methods at the momentStdio, שהוא בעצם שורת פקודות, ו- SSE.
אני לא ממש מבין למה הם בחרו ב- SSE - זה בעצם בקשה ארוכה שאינה נגמרת ומעבירה אירועים ללקוח.
הבעיה עם שיטה זו היא כי כדי לשלוח מידע בחזרה לשרת, עליך לשלוח בקשה דואר נוספת (כי SSE היא תקשורת חד-צדדית), כלומר עליך לשמור על המצב.
בדוגמה שלהם, הם מחזיקים את המצב בזיכרון של האפליקציה, ונחשו מה?
יש להם מצב שינה מובנה, ואתה לא צריך לשמור על מצב עבור זה.
חפירה ב
חפצתי ב- 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 {};
}
}
Decorators FTW 🎖️
זה בשבילך אם אתה מעריץ גדול של מסגרות OOP כמו NestJS/Laravel/Spring.
@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}`,
},
];
}
את כל הקוד ניתן למצוא בפוסטים כאן: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 לעשות דברים שונים לפני שהוא מקבל גישה לדברים שלנו.
בכל פעם שאמרתי לקורסור לתזמן עבורי פוסט, הוא ניסה לתזמן אותו ל-2024.
הייתי צריך להעביר כמה פרטים Config, אז יצרתי אתPOSTIZ_CONFIGURATION_PRERUN
מקווה, LLM תמיד יקרא את זה לפני שאתה עושה דברים.
אבל זה התעלם מזה פעמים רבות (טיפוסי), אז הייתי צריך להיות יצירתי.POSTIZ_SCHEDULE_POST
הוספתי נכס חדש בשםconfigId
ושינתה את שם הכלי Config לPOSTIZ_GET_CONFIG_ID.
התוצאה של Config היא:id: ${makeId(10)} Today date is ${dayjs.utc().format()}
זה הכריח את LLM תמיד לקרוא לו קודם לכן, ואת התאריך היה קבוע! :)
זה היה אפילו יותר טוב בשבילי כי ידעתי שזה ישלח לי תאריכים UTC מעכשיו.
שימוש מקרים
אני חושב שזה עובד הכי טוב כאשר הוא משולב עם מספר קבוצות של כלים, למשל:
- →
- התחבר ל- Cursor ולבקש ממנו לתזמן פוסט על העבודה שלך היום. →
- צור קשר עם Notion ולבקש לתזמן את כל העבודה האחרונה של הצוות ברשתות החברתיות - בדוק את Composio MCPs. →
- חיבר אותו לכל מערכת SaaS שיש לה CopilotKit ותזמן פוסטים בהתבסס על האפליקציה. →
תגית: MCP
פוסטיםהוא כלי התזמון החברתי הפתוח ביותר - ועכשיו התזמורת היחידה המציעה MCP (באופן טבעי, לא עם Zapier או משהו כזה)
עם MCP החדש, אתה יכול לתזמן את כל הפוסטים שלך מ Cursor / Windsurf ו Anthropic לקוחות.
הכל 100% בחינם כמובן :)
אם אתה אוהב את זה, אנא אל תשכח לכוכב אותנו ⭐️HTTPS://github.com/Gitroomhq/Postiz-app