| name | pikku-mcp |
| description | Use when exposing Pikku functions as MCP tools, resources, or prompts for AI assistants. Covers mcp: true flag, pikkuMCPResourceFunc, pikkuMCPPromptFunc, and MCP wire object. TRIGGER when: code uses mcp: true or pikkuMCPResourceFunc/pikkuMCPPromptFunc, user asks about MCP, Model Context Protocol, AI tool integration, or exposing functions to Claude/ChatGPT. DO NOT TRIGGER when: user asks about AI agents (use pikku-ai-agent) or general function definitions (use pikku-concepts). |
| installGroups | ["core"] |
Pikku MCP Wiring
Agent Operating Procedure
Use this skill as an execution checklist, not reference material.
- Discover before editing. Prefer OpenCode tools such as
pikku-meta when available; otherwise run the relevant pikku meta ... --json command and inspect only the focused output you need.
- Identify the source files that own the behavior. Do not start by reading generated output,
.pikku, node_modules, vendored packages, or broad build artifacts.
- Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
- Validate with the narrowest relevant command first, then run
pikku-verify or pikku all when functions, wirings, schemas, or generated clients may have changed.
- If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
Expose Pikku functions as Model Context Protocol (MCP) tools, resources, and prompts for AI assistants like Claude, ChatGPT, and others.
Before You Start
pikku info functions --verbose
pikku info tags --verbose
See pikku-concepts for the core mental model.
API Reference
MCP Tools (simplest approach)
Add mcp: true to any existing pikkuFunc to expose it as an MCP tool:
const myFunc = pikkuFunc({
description: string,
input: ZodSchema,
output: ZodSchema,
mcp: true,
func: async (services, data) => { ... },
})
MCP Resources (pikkuMCPResourceFunc)
import { pikkuMCPResourceFunc } from '#pikku'
const resource = pikkuMCPResourceFunc({
uri: string,
title: string,
description?: string,
func: async (services, data, { mcp }) => {
return [{ uri: mcp.uri!, text: JSON.stringify(result) }]
},
})
MCP Prompts (pikkuMCPPromptFunc)
import { pikkuMCPPromptFunc } from '#pikku'
const prompt = pikkuMCPPromptFunc({
name: string,
description: string,
func: async (services, data) => {
return [
{
role: 'user',
content: { type: 'text', text: '...' },
},
]
},
})
MCP Wire Object
Inside MCP-enabled functions, wire.mcp provides:
mcp.uri
mcp.sendResourceUpdated(uri)
mcp.enableTools({ toolName: true })
Usage Patterns
Expose Existing Functions as MCP Tools
The simplest path — add mcp: true to any function:
export const createTodo = pikkuFunc({
description: 'Create a new todo item',
input: CreateTodoInput,
output: CreateTodoOutput,
mcp: true,
func: async ({ db }, { text, priority }) => {
return await db.createTodo({ text, priority })
},
})
MCP Resources with URI Templates
export const getTodo = pikkuMCPResourceFunc({
uri: 'todos/{id}',
title: 'Todo Details',
description: 'Get a todo by ID',
func: async ({ db }, { id }, { mcp }) => {
const todo = await db.getTodo(id)
return [{ uri: mcp.uri!, text: JSON.stringify(todo) }]
},
})
MCP Prompts
export const codeReview = pikkuMCPPromptFunc({
name: 'codeReview',
description: 'Generate a code review prompt',
func: async ({}, { filePath, context }) => {
return [
{
role: 'user',
content: {
type: 'text',
text: `Review ${filePath}. Context: ${context}`,
},
},
]
},
})
Dynamic Tool Control
export const manageTodos = pikkuFunc({
description: 'Manage todo items',
input: ManageTodosInput,
output: ManageTodosOutput,
mcp: true,
func: async ({ db }, { action, id }, { mcp }) => {
if (action === 'delete') {
await db.deleteTodo(id)
mcp.sendResourceUpdated(`todos/${id}`)
await mcp.enableTools({ archiveTodos: true })
return { deleted: true }
}
},
})
MCP Server Setup
import { PikkuMCPServer } from '@pikku/modelcontextprotocol'
const server = new PikkuMCPServer(config, singletonServices, createWireServices)
await server.init()
await server.start()
Complete Example
export const listTodos = pikkuSessionlessFunc({
description: 'List all todo items',
input: ListTodosInput,
output: ListTodosOutput,
mcp: true,
func: async ({ db }, { status }) => {
return { todos: await db.listTodos(status) }
},
})
export const createTodo = pikkuFunc({
description: 'Create a new todo item',
input: CreateTodoInput,
output: CreateTodoOutput,
mcp: true,
func: async ({ db }, { text, priority }) => {
return await db.createTodo({ text, priority })
},
})
export const completeTodo = pikkuFunc({
description: 'Mark a todo as complete',
input: CompleteTodoInput,
output: CompleteTodoOutput,
mcp: true,
func: async ({ db }, { todoId }) => {
return await db.completeTodo(todoId)
},
})
export const getTodoResource = pikkuMCPResourceFunc({
uri: 'todos/{id}',
title: 'Todo Details',
description: 'Get details of a specific todo',
func: async ({ db }, { id }, { mcp }) => {
const todo = await db.getTodo(id)
return [{ uri: mcp.uri!, text: JSON.stringify(todo) }]
},
})
export const planDayPrompt = pikkuMCPPromptFunc({
name: 'planDay',
description: 'Create a daily plan based on pending todos',
func: async ({ db }, {}) => {
const { todos } = await db.listTodos('pending')
return [
{
role: 'user',
content: {
type: 'text',
text: `Plan my day. Here are my pending todos:\n${todos.map((t) => `- ${t.text} (${t.priority})`).join('\n')}`,
},
},
]
},
})