agent-chef-mcp 1.0.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.
- package/LICENSE +9 -0
- package/README.md +93 -0
- package/catalog.json +5600 -0
- package/package.json +53 -0
- package/server.js +55 -0
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-chef-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Family meal planning run by your own AI agent: weekly dinners, household votes, grocery list minus the pantry. Stdio MCP server for the hosted Agent Chef service (https://agentchef.net/mcp).",
|
|
5
|
+
"homepage": "https://agentchef.net",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/coryshaw/agent-chef-mcp"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"bin": {
|
|
13
|
+
"agent-chef-mcp": "server.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"server.js",
|
|
17
|
+
"catalog.json",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"start": "node server.js",
|
|
23
|
+
"sync": "node scripts/sync-catalog.mjs",
|
|
24
|
+
"test": "node scripts/test.mjs"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"mcp",
|
|
34
|
+
"mcp-server",
|
|
35
|
+
"model-context-protocol",
|
|
36
|
+
"claude",
|
|
37
|
+
"chatgpt",
|
|
38
|
+
"cursor",
|
|
39
|
+
"codex",
|
|
40
|
+
"meal-planning",
|
|
41
|
+
"recipes",
|
|
42
|
+
"grocery-list",
|
|
43
|
+
"family",
|
|
44
|
+
"ai-agent"
|
|
45
|
+
],
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/coryshaw/agent-chef-mcp/issues",
|
|
51
|
+
"email": "support@agentchef.net"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/server.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Agent Chef MCP server (stdio). Runs locally for clients that only speak stdio, or for directories that
|
|
3
|
+
// build and test servers in a container. The tool catalog ships with the package (catalog.json), so
|
|
4
|
+
// initialize / tools/list / prompts/list work offline. Tool calls are executed by the hosted service at
|
|
5
|
+
// https://agentchef.net/mcp on behalf of the household identified by AGENT_CHEF_API_KEY.
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
|
|
13
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const catalog = JSON.parse(readFileSync(join(here, "catalog.json"), "utf8"));
|
|
15
|
+
const REMOTE = process.env.AGENT_CHEF_URL ?? "https://agentchef.net/mcp";
|
|
16
|
+
const KEY = (process.env.AGENT_CHEF_API_KEY ?? "").trim();
|
|
17
|
+
|
|
18
|
+
const NO_KEY = `Agent Chef needs an API key to act on a household. Sign in at https://agentchef.net, open Settings → Agents, create a key, and start this server with AGENT_CHEF_API_KEY=ac_... (free trial, no card). Alternatively connect https://agentchef.net/mcp directly with OAuth in clients that support it.`;
|
|
19
|
+
|
|
20
|
+
const server = new Server({ name: catalog.server?.name ?? "agent-chef", version: catalog.server?.version ?? "0.0.0" }, {
|
|
21
|
+
capabilities: { tools: {}, prompts: {} },
|
|
22
|
+
instructions: catalog.instructions,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: catalog.tools }));
|
|
26
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: catalog.prompts }));
|
|
27
|
+
|
|
28
|
+
server.setRequestHandler(GetPromptRequestSchema, async (req) => {
|
|
29
|
+
const p = catalog.prompts.find((x) => x.name === req.params.name);
|
|
30
|
+
if (!p) throw new Error(`Unknown prompt ${req.params.name}`);
|
|
31
|
+
return { description: p.description, messages: [{ role: "user", content: { type: "text", text: `${catalog.instructions}\n\nNow run the loop: call next_actions and execute what it returns.` } }] };
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
35
|
+
if (!catalog.tools.some((t) => t.name === req.params.name)) return { isError: true, content: [{ type: "text", text: `Unknown tool ${req.params.name}` }] };
|
|
36
|
+
if (!KEY) return { isError: true, content: [{ type: "text", text: NO_KEY }] };
|
|
37
|
+
let res;
|
|
38
|
+
try {
|
|
39
|
+
res = await fetch(REMOTE, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: { "content-type": "application/json", accept: "application/json, text/event-stream", authorization: `Bearer ${KEY}` },
|
|
42
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: req.params }),
|
|
43
|
+
signal: AbortSignal.timeout(60_000),
|
|
44
|
+
});
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return { isError: true, content: [{ type: "text", text: `Could not reach ${REMOTE}: ${e.message}` }] };
|
|
47
|
+
}
|
|
48
|
+
if (res.status === 401) return { isError: true, content: [{ type: "text", text: `Agent Chef rejected the API key (401). Create a new one at https://agentchef.net/app/settings/agents and restart with AGENT_CHEF_API_KEY set.` }] };
|
|
49
|
+
const body = await res.json().catch(() => null);
|
|
50
|
+
if (!body) return { isError: true, content: [{ type: "text", text: `Agent Chef returned HTTP ${res.status} with a non-JSON body.` }] };
|
|
51
|
+
if (body.error) return { isError: true, content: [{ type: "text", text: body.error.message ?? JSON.stringify(body.error) }] };
|
|
52
|
+
return body.result;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await server.connect(new StdioServerTransport());
|