mcpserver

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package mcpserver exposes CodeMode as exactly three official MCP tools.

The adapter resolves a trusted subject through the required InvocationResolver before every operation, ignores untrusted client metadata, and projects failures to stable coarse tool text. StaticSubject supports single-user process-owned identity; multi-user hosts must resolve each authenticated request separately. The adapter does not proxy arbitrary downstream MCP tools.

Example (OfficialTransport)

Example_officialTransport connects official MCP sessions and calls execute.

This in-memory sample has one process-owned identity, matching a single-user stdio host. Multi-user hosts must resolve each request from authenticated, host-owned context instead. authz.AllowAll is deliberate in this sample; production hosts normally supply policy.

package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/modelcontextprotocol/go-sdk/mcp"

	"github.com/meigma/codemode"
	"github.com/meigma/codemode/authz"
	"github.com/meigma/codemode/mcpserver"
)

func main() {
	// lookupInput is the records.lookup argument contract.
	type lookupInput struct {
		// Key is the required record identifier.
		Key string `json:"key"`

		// Limit is the optional result bound.
		Limit *int64 `json:"limit,omitempty"`
	}

	// lookupOutput is the records.lookup handler result.
	type lookupOutput struct {
		// Key is the looked-up record identifier.
		Key string `json:"key"`

		// Count is the resolved optional limit, or zero when omitted.
		Count int64 `json:"count"`
	}

	builder := codemode.New(codemode.Options{Authorizer: authz.AllowAll()})
	codemode.Register(builder, codemode.Capability[lookupInput, lookupOutput]{
		Name:    "records.lookup",
		Summary: "Look up one record by key.",
		Handler: func(_ context.Context, _ authz.Subject, input lookupInput) (lookupOutput, error) {
			count := int64(0)
			if input.Limit != nil {
				count = *input.Limit
			}
			return lookupOutput{Key: input.Key, Count: count}, nil
		},
	})

	root, err := builder.Build()
	if err != nil {
		panic(err)
	}

	mcpServer, err := mcpserver.New(root, mcpserver.StaticSubject(authz.Subject{ID: "example-user"}))
	if err != nil {
		panic(err)
	}

	serverTransport, clientTransport := mcp.NewInMemoryTransports()
	serverSession, err := mcpServer.Connect(context.Background(), serverTransport, nil)
	if err != nil {
		panic(err)
	}
	client := mcp.NewClient(&mcp.Implementation{Name: "example-client", Version: "1"}, nil)
	clientSession, err := client.Connect(context.Background(), clientTransport, nil)
	if err != nil {
		panic(err)
	}

	result, err := clientSession.CallTool(context.Background(), &mcp.CallToolParams{
		Name: "execute",
		Arguments: map[string]any{
			"source": `
def main():
    return records.lookup(key="alpha", limit=2)
`,
		},
	})
	if err != nil {
		panic(err)
	}
	if result.IsError {
		panic(fmt.Sprint(result.Content))
	}

	encoded, err := json.Marshal(result.StructuredContent)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(encoded))

	if err := clientSession.Close(); err != nil {
		panic(err)
	}
	if err := serverSession.Close(); err != nil {
		panic(err)
	}
}
Output:
{"result":{"count":2,"key":"alpha"}}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(service Service, resolver InvocationResolver) (*mcp.Server, error)

New constructs an official MCP server that exposes exactly search_api, describe_api, and execute.

New rejects a nil or typed-nil Service or InvocationResolver. The returned server has no generic downstream MCP forwarding path. Client request metadata is untrusted and ignored.

Types

type InvocationResolver

type InvocationResolver interface {
	// Resolve returns the authenticated subject for the current request.
	//
	// A resolver failure or empty subject ID stops the request before discovery or
	// execution. Resolve must not return credential material.
	Resolve(ctx context.Context) (authz.Subject, error)
}

InvocationResolver resolves the trusted invocation subject from host-owned Go context.

Implementations must read only typed trusted context established by middleware or process composition. They must not derive identity from program data, tool arguments, or untrusted request metadata.

func ContextSubject

func ContextSubject() InvocationResolver

ContextSubject returns a resolver for subjects installed with authz.WithSubject.

Authentication middleware remains responsible for validating credentials and installing the subject. Client-controlled tool arguments, program source, and MCP request metadata cannot set or replace the stored subject.

func StaticSubject

func StaticSubject(subject authz.Subject) InvocationResolver

StaticSubject returns a resolver that uses subject for every invocation.

StaticSubject is suitable only when process ownership is the authentication boundary, such as a single-user stdio server. Multi-user hosts must resolve a distinct authenticated subject for each request and must not use StaticSubject.

type Service

type Service interface {
	// Search returns a bounded relevance-ranked scan of enabled capabilities.
	Search(query string) (codemode.SearchResponse, error)

	// Describe returns one exact enabled capability description or a not-found error.
	Describe(name codemode.CapabilityName) (codemode.Description, error)

	// Execute runs one bounded program for a trusted authenticated subject and returns only main's final value.
	Execute(ctx context.Context, subject authz.Subject, program codemode.Program) (any, error)
}

Service is the inbound adapter's view of an immutable CodeMode server.

The root *codemode.Server implements this port. The adapter does not re-enforce catalog bounds, hidden-capability filtering, or execution restrictions.

Directories

Path Synopsis
Package mocks contains generated test doubles for MCP adapter ports.
Package mocks contains generated test doubles for MCP adapter ports.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL